retold-data-service 2.0.21 → 2.0.23
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.
- package/.quackage-comprehension-loader.json +19 -0
- package/bin/retold-data-service-clone.js +4 -1
- package/generate-bookstore-comprehension.js +645 -0
- package/package.json +7 -7
- package/source/Retold-Data-Service.js +30 -2
- package/source/services/comprehension-loader/ComprehensionLoader-Command-Load.js +345 -0
- package/source/services/comprehension-loader/ComprehensionLoader-Command-Schema.js +97 -0
- package/source/services/comprehension-loader/ComprehensionLoader-Command-Session.js +221 -0
- package/source/services/comprehension-loader/ComprehensionLoader-Command-WebUI.js +57 -0
- package/source/services/comprehension-loader/Retold-Data-Service-ComprehensionLoader.js +536 -0
- package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader-Configuration.json +9 -0
- package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader.js +86 -0
- package/source/services/comprehension-loader/pict-app/Pict-ComprehensionLoader-Bundle.js +6 -0
- package/source/services/comprehension-loader/pict-app/providers/Pict-Provider-ComprehensionLoader.js +760 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Layout.js +360 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Load.js +472 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Schema.js +119 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Session.js +269 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Source.js +330 -0
- package/source/services/comprehension-loader/web/comprehension-loader.js +6794 -0
- package/source/services/comprehension-loader/web/comprehension-loader.js.map +1 -0
- package/source/services/comprehension-loader/web/comprehension-loader.min.js +2 -0
- package/source/services/comprehension-loader/web/comprehension-loader.min.js.map +1 -0
- package/source/services/comprehension-loader/web/index.html +17 -0
- package/source/services/data-cloner/DataCloner-Command-Schema.js +407 -15
- package/source/services/data-cloner/Retold-Data-Service-DataCloner.js +59 -1
- package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +1 -0
- package/source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js +125 -5
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js +18 -8
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Deploy.js +104 -1
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +1 -1
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js +12 -0
- package/source/services/data-cloner/web/data-cloner.js +201 -139
- package/source/services/data-cloner/web/data-cloner.js.map +1 -1
- package/source/services/data-cloner/web/data-cloner.min.js +1 -1
- package/source/services/data-cloner/web/data-cloner.min.js.map +1 -1
- package/test/RetoldDataService_tests.js +225 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["data-cloner.min.js","node_modules/browser-pack/_prelude.js","node_modules/fable-serviceproviderbase/package.json","node_modules/fable-serviceproviderbase/source/Fable-ServiceProviderBase.js","node_modules/pict-application/package.json","node_modules/pict-application/source/Pict-Application.js","node_modules/pict-provider/package.json","node_modules/pict-provider/source/Pict-Provider.js","node_modules/pict-section-histogram/source/Pict-Section-Histogram-DefaultConfiguration.js","node_modules/pict-section-histogram/source/Pict-Section-Histogram.js","node_modules/pict-section-histogram/source/renderers/Pict-Histogram-Renderer-Browser.js","node_modules/pict-section-histogram/source/renderers/Pict-Histogram-Renderer-CLI.js","node_modules/pict-section-histogram/source/renderers/Pict-Histogram-Renderer-ConsoleUI.js","node_modules/pict-view/package.json","node_modules/pict-view/source/Pict-View.js","node_modules/process/browser.js","source/services/data-cloner/pict-app/Pict-Application-DataCloner-Configuration.json","source/services/data-cloner/pict-app/Pict-Application-DataCloner.js","source/services/data-cloner/pict-app/Pict-DataCloner-Bundle.js","source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Deploy.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Schema.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Session.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Sync.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-ViewData.js"],"names":["f","exports","module","define","amd","window","global","self","this","dataCloner","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","name","version","description","main","scripts","start","test","tests","coverage","build","types","check","mocha","diff","extension","package","reporter","slow","timeout","ui","repository","type","url","keywords","author","license","bugs","homepage","devDependencies","fable","quackage","typescript","libPackage","FableServiceProviderBase","constructor","pFable","pOptions","pServiceHash","UUID","options","services","servicesMap","isFable","connectFable","_PackageFableServiceProvider","getUUID","Math","floor","random","serviceType","Hash","tmpErrorMessage","console","log","Logging","static","CoreServiceProviderBase","lint","eslint","pict","dependencies","libFableServiceBase","defaultPictSettings","Name","MainViewportViewIdentifier","MainViewportRenderableHash","MainViewportDestinationAddress","MainViewportDefaultDataAddress","AutoSolveAfterInitialize","AutoRenderMainViewportViewAfterInitialize","AutoRenderViewsAfterInitialize","AutoLoginAfterInitialize","AutoLoadDataAfterLogin","ConfigurationOnlyViews","Manifests","IdentifierAddressPrefix","tmpCarryOverConfiguration","settings","PictApplicationConfiguration","super","Object","assign","JSON","parse","stringify","_Package","AppData","Bundle","initializeTimestamp","lastSolvedTimestamp","lastLoginTimestamp","lastMarshalFromViewsTimestamp","lastMarshalToViewsTimestamp","lastAutoRenderTimestamp","lastLoadDataTimestamp","tmpManifestKeys","keys","tmpManifestKey","instantiateServiceProvider","onPreSolve","LogNoisiness","trace","onPreSolveAsync","fCallback","onBeforeSolve","onBeforeSolveAsync","onSolve","onSolveAsync","solve","tmpLoadedProviders","providers","tmpProvidersToSolve","tmpProvider","AutoSolveWithApp","push","sort","b","AutoSolveOrdinal","tmpLoadedViews","views","tmpViewsToSolve","tmpView","AutoInitialize","AutoInitializeOrdinal","onAfterSolve","getTimeStamp","solveAsync","tmpAnticipate","instantiateServiceProviderWithoutRegistration","anticipate","bind","tmpCallback","warn","pError","error","onAfterSolveAsync","wait","onBeforeLoginAsync","onLoginAsync","loginAsync","onAfterLoginAsync","fNext","isLoggedIn","loadDataAsync","onBeforeLoadDataAsync","onLoadDataAsync","tmpProvidersToLoadData","AutoLoadDataWithApp","AutoLoadDataOrdinal","onAfterLoadDataAsync","onBeforeSaveDataAsync","onSaveDataAsync","saveDataAsync","tmpProvidersToSaveData","AutoSaveDataWithApp","AutoSaveDataOrdinal","onAfterSaveDataAsync","lastSaveDataTimestamp","onBeforeInitialize","onBeforeInitializeAsync","onInitialize","onInitializeAsync","initialize","LogControlFlow","tmpViewIdentifier","ViewIdentifier","info","addView","tmpProvidersToInitialize","tmpViewsToInitialize","onAfterInitialize","render","onCompletionOfInitialize","initializeAsync","onCompletionOfInitializeAsync","onAfterInitializeAsync","renderMainViewportAsync","message","stack","onBeforeMarshalFromViews","onBeforeMarshalFromViewsAsync","onMarshalFromViews","onMarshalFromViewsAsync","marshalFromViews","tmpViewsToMarshalFromViews","marshalFromView","onAfterMarshalFromViews","marshalFromViewsAsync","marshalFromViewAsync","onAfterMarshalFromViewsAsync","onBeforeMarshalToViews","onBeforeMarshalToViewsAsync","onMarshalToViews","onMarshalToViewsAsync","marshalToViews","tmpViewsToMarshalToViews","marshalToView","onAfterMarshalToViews","marshalToViewsAsync","marshalToViewAsync","onAfterMarshalToViewsAsync","onBeforeRender","onBeforeRenderAsync","pViewIdentifier","pRenderableHash","pRenderDestinationAddress","pTemplateDataAddress","tmpRenderableHash","tmpRenderDestinationAddress","tmpTemplateDataAddress","PictView","onRender","onAfterRender","onRenderAsync","renderAsync","tmpRenderAnticipate","newAnticipate","onAfterRenderAsync","renderMainViewport","renderAutoViews","AutoRenderOrdinal","AutoRender","renderAutoViewsAsync","isPictApplication","defaultPictProviderSettings","ProviderIdentifier","Templates","tmpDefaultTemplate","hasOwnProperty","Source","TemplateProvider","addDefaultTemplate","Prefix","Postfix","Template","Stack","onPreRender","onPreRenderAsync","RenderOnLoad","DefaultRenderable","DefaultDestinationAddress","Renderables","RenderableHash","TemplateHash","DestinationAddress","TargetElementAddress","DataAddress","Bins","LabelProperty","ValueProperty","Orientation","RenderMode","MaxBarSize","BarThickness","BarGap","FillContainer","ShowValues","ShowLabels","LabelInterval","BarColor","SelectedBarColor","SelectionRangeColor","Selectable","SelectionMode","SelectionDataAddress","InitialSelection","BarCharacter","BarPartialCharacters","EmptyCharacter","SliderCharacter","SliderHandleCharacter","TextWidth","TextHeight","CSS","libPictViewClass","_DefaultConfiguration","libRendererBrowser","libRendererConsoleUI","libRendererCLI","initialRenderComplete","_selectedIndices","Set","_selectionRangeStart","_selectionRangeEnd","_renderer","_resolveRenderer","_applyInitialSelection","setSelection","tmpBins","getBins","max","_syncSelectionFromRange","tmpAddressSpace","Fable","Pict","Options","tmpData","manifest","getValueByHash","Array","isArray","setBins","pBins","setValueByHash","isIndexSelected","pIndex","has","isIndexInRange","getSelection","tmpIndices","Mode","RangeStart","RangeEnd","SelectedIndices","StartLabel","EndLabel","from","pSelection","Start","End","_writeSelectionToAddress","handleBarClick","clear","add","delete","onSelectionChange","renderHistogram","handleRangeBarClick","abs","min","pRenderable","CSSMap","injectCSS","onAfterInitialRender","wireEvents","setOrientation","pOrientation","setRenderMode","pRenderMode","toText","renderVertical","renderHorizontal","default_configuration","renderers","browser","consoleui","cli","buildBarGroupHTML","pBin","pBarSize","pIsSelected","pInRange","pLabelWidth","tmpLabel","tmpValue","tmpVertical","tmpBarColor","tmpSelectableClass","tmpSelectedClass","tmpInRangeClass","tmpFillMode","tmpBarStyle","tmpGroupWidth","tmpGroupStyle","tmpHTML","wireRangeHandle","pView","pHandle","pContainer","tmpHandleType","getAttribute","tmpDragging","onPointerMove","pEvent","tmpBounds","tmpSlider","querySelector","size","tmpRect","getBoundingClientRect","left","width","top","height","getSliderBounds","tmpPct","clientX","clientY","tmpIndex","round","onPointerUp","document","removeEventListener","addEventListener","preventDefault","ContentAssignment","assignContent","tmpMaxValue","tmpVal","tmpOrientationClass","tmpFillClass","tmpLabelWidth","tmpEstWidth","String","tmpBarSize","tmpIsSelected","tmpInRange","tmpLabelInterval","tmpTargetElementSet","getElement","tmpContainerWidth","clientWidth","tmpBarWidth","ceil","tmpSpan","buildFillLabelRow","tmpRangeStart","tmpRangeEnd","tmpMax","tmpStartPct","tmpEndPct","buildRangeSliderHTML","tmpContainer","tmpBars","querySelectorAll","parseInt","currentTarget","isNaN","tmpHandles","process","ANSI_COLORS","black","red","green","yellow","blue","magenta","cyan","white","reset","bold","dim","colorToAnsi","pColor","tmpLower","toLowerCase","charAt","tmpR","substring","tmpG","tmpB","tmpOptions","tmpHeight","tmpBarChar","tmpPartials","tmpSelectedColor","tmpRangeColor","tmpReset","tmpValueAxisWidth","tmpLines","tmpRow","tmpLine","padLeft","tmpBarHeight","tmpFullRows","tmpFraction","tmpColor","tmpChar","tmpAxisLine","tmpLabelLine","padCenter","tmpStart","tmpEnd","tmpStartLabel","tmpEndLabel","join","tmpWidth","tmpMaxLabelLen","tmpBarLen","tmpBar","j","padRight","pStr","pLen","tmpStr","tmpText","stdout","write","_process","tmpEmptyChar","tmpRangeLine","tmpFullChars","tmpMarker","tmpValueStr","defaultPictViewSettings","DefaultTemplateRecordAddress","CSSHash","CSSProvider","CSSPriority","DefaultTemplates","tmpHashIsUUID","lastRenderedTimestamp","lastMarshalFromViewTimestamp","lastMarshalToViewTimestamp","instantiateServiceProviderIfNotExists","tmpTemplate","addTemplate","tmpCSSHash","tmpCSSProvider","addCSS","renderables","tmpRenderable","addRenderable","pTemplateHash","pDefaultTemplateRecordAddress","pDefaultDestinationAddress","pRenderMethod","ContentDestinationAddress","RenderMethod","onBeforeProject","onBeforeProjectAsync","buildRenderOptions","pTemplateRecordAddress","tmpRenderOptions","Valid","Renderable","RecordAddress","Record","DataProvider","getDataByAddress","undefined","assignRenderContent","pContent","projectContent","TestAddress","pRootRenderable","renderWithScope","pScope","tmpRecordAddress","tmpRecord","TransactionHash","RootRenderableViewHash","TransactionTracking","registerTransaction","Content","parseTemplateByHash","RootRenderable","onProject","onAfterProject","renderWithScopeAsync","fOnBeforeRenderCallback","fAsyncTemplateCallback","onProjectAsync","onAfterProjectAsync","renderDefaultAsync","basicRender","basicRenderWithScope","basicRenderAsync","basicRenderWithScopeAsync","pushToTransactionQueue","ViewHash","tmpTransactionQueue","clearTransactionQueue","tmpEvent","Data","queue","event","onBeforeMarshalFromView","onBeforeMarshalFromViewAsync","onMarshalFromView","onMarshalFromViewAsync","onAfterMarshalFromView","onAfterMarshalFromViewAsync","onBeforeMarshalToView","onBeforeMarshalToViewAsync","onMarshalToView","onMarshalToViewAsync","onAfterMarshalToView","onAfterMarshalToViewAsync","isPictView","cachedSetTimeout","cachedClearTimeout","defaultSetTimout","defaultClearTimeout","runTimeout","fun","setTimeout","clearTimeout","currentQueue","draining","queueIndex","cleanUpNextTick","concat","drainQueue","len","run","marker","runClearTimeout","Item","array","noop","nextTick","args","arguments","prototype","apply","title","env","argv","versions","on","addListener","once","off","removeListener","removeAllListeners","emit","prependListener","prependOnceListener","listeners","binding","cwd","chdir","dir","umask","pict_configuration","Product","libPictApplication","libProvider","libViewLayout","libViewConnection","libViewSession","libViewSchema","libViewDeploy","libViewSync","libViewExport","libViewViewData","libViewHistogram","addProvider","DataCloner","FetchedTables","DeployedTables","LastReport","ServerBusyAtLoad","SyncPollTimer","LiveStatusTimer","StatusDetailExpanded","StatusDetailTimer","StatusDetailData","LastLiveStatus","PersistFields","initPersistence","onProviderChange","restoreDeployedTables","startLiveStatusPolling","initAccordionPreviews","updateAllPreviews","collapseAllSections","initAutoProcess","DataClonerApplication","libPictProvider","api","pMethod","pPath","pBody","tmpOpts","method","headers","body","fetch","then","pResponse","json","setStatus","pElementId","pMessage","pType","tmpEl","getElementById","className","textContent","style","display","escapeHtml","tmpDiv","createElement","appendChild","createTextNode","innerHTML","setSectionPhase","pSection","pState","classList","value","tmpPreview1","tmpServerURL","tmpUserName","tmpPreview2","tmpTableChecks","tmpSchemaURL","tmpDeployedEl","tmpDeployedText","indexOf","tmpSyncMode","tmpSyncPreview","checked","tmpMaxRecords","tmpLogFile","tmpExportParts","tmpViewTable","tmpSelf","tmpPreviewFields","tmpHandler","tmpCheckboxes","forEach","pEl","saveField","pFieldId","localStorage","setItem","restoreFields","tmpPersistFields","tmpId","tmpSaved","getItem","tmpSyncDeleted","tmpSolrSecure","tmpAdvancedIDPagination","pId","tmpSyncDeletedEl","tmpSolrSecureEl","tmpAdvancedIDPaginationEl","tmpAutoIds","tmpAppData","clearInterval","pollLiveStatus","setInterval","pData","renderLiveStatus","catch","Phase","Message","TotalSynced","TotalRecords","tmpMsg","tmpMeta","tmpProgressFill","tmpWasExpanded","contains","tmpMetaParts","Elapsed","ETA","TotalTables","Completed","tmpSynced","toString","replace","PreCountGrandTotal","tmpGrandTotal","PreCountProgress","Counted","tmpCountedSoFar","Errors","tmpTablePct","ActiveProgress","Total","Synced","tmpLayoutView","toggleStatusDetail","renderStatusDetail","pReportData","ReportVersion","onStatusDetailExpanded","pollStatusDetail","onStatusDetailCollapsed","renderCountingPhaseDetail","pPreCountProgress","tmpTables","Tables","tmpCounted","tmpTotal","tmpRunningTotal","tmpHtml","tmpT","Count","tmpCountFmt","formatNumber","tmpTimeFmt","ElapsedMs","toFixed","tmpRemaining","tmpLiveStatus","tmpStatusData","tmpReport","tmpHistContainer","tmpThroughputSamples","tmpEventLog","tmpIsLive","ThroughputSamples","EventLog","tmpRunning","tmpPending","tmpCompleted","tmpErrors","tmpTableNames","tmpName","Status","tmpOp","tmpSyncedFmt","tmpTotalFmt","renderCompletedRow","renderErrorRow","updateThroughputHistogram","pSamples","tmpRawDeltas","tmpDelta","synced","delta","tmpMaxBars","tmpAggregated","tmpBucketSize","tmpSum","tmpLastT","tmpHasData","tmpStartT","tmpElapsedSec","Label","formatElapsed","Value","tmpHistView","pSec","tmpS","tmpH","tmpM","formatCompact","pNum","pOp","tmpNew","New","tmpUpdated","Updated","tmpUnchanged","Unchanged","tmpDeleted","Deleted","tmpServerTotal","ServerTotal","tmpUnchangedPct","tmpNewPct","tmpUpdatedPct","tmpDeletedPct","tmpPctSum","pEventLog","ErrorMessage","tmpRelevantLogs","tmpLog","Table","Type","tmpTimestamp","Timestamp","saveDeployedTables","tmpRaw","populateViewTableDropdown","startPolling","runAutoProcessChain","tmpDelay","tmpStepDelay","connectProvider","goAction","fetchSchema","deploySchema","startSync","libPictView","tmpProviders","getProviderConfig","tmpConfig","SQLiteFilePath","trim","host","port","user","password","database","connectionLimit","server","core","path","secure","maxPoolSize","RocksDBFolder","StorageFolder","Provider","Config","tmpConnInfo","Success","testConnection","checkConnectionStatus","Connected","tmpSelectedTables","getSelectedTables","TablesDeployed","resetDatabase","confirm","tmpSyncProgress","buildConfigObject","LocalDatabase","tmpDbConfig","RemoteSession","ServerURL","tmpAuthMethod","AuthenticationMethod","tmpAuthURI","AuthenticationURITemplate","tmpCheckURI","CheckSessionURITemplate","tmpCookieName","CookieName","tmpCookieValueAddr","CookieValueAddress","tmpCookieValueTemplate","CookieValueTemplate","tmpLoginMarker","CheckSessionLoginMarker","tmpPassword","Credentials","UserName","Password","SchemaURL","Sync","PageSize","SyncDeletedRecords","tmpPrecision","DateTimePrecisionMS","MaxRecords","UseAdvancedIDPagination","buildMeadowIntegrationConfig","UserID","Destination","MySQL","MSSQL","ConnectionPoolLimit","SchemaPath","DefaultSyncMode","tmpMdwintPrecision","SyncEntityList","SyncEntityOptions","SessionManager","Sessions","tmpSessionConfig","AuthenticationRequestBody","CheckSessionLoginMarkerType","tmpUrlObj","URL","DomainMatch","SourceAPI","generateConfig","tmpJson","tmpTextarea","tmpLogFlag","tmpMaxFlag","tmpExportMax","tmpCliDiv","tmpOneShotDiv","tmpOneShot","tmpMdwintConfig","tmpMdwintJSON","copyConfig","navigator","clipboard","writeText","copyCLI","tmpCmd","copyOneShot","downloadConfig","tmpBlob","Blob","tmpAnchor","href","createObjectURL","download","click","revokeObjectURL","copyMdwintConfig","copyMdwintCLI","downloadMdwintConfig","toggleSection","pSectionId","tmpCard","toggle","expandAllSections","tmpCards","remove","tmpDetail","tmpMessage","tmpToggle","tmpBody","TableCount","renderTableList","loadSavedSelections","saveSelections","tmpSelected","updateSelectionCount","tmpFetchedTables","tmpCount","tmpSavedSet","setAttribute","tmpCheckbox","id","htmlFor","filterTableList","tmpFilter","tmpItems","children","selectAllTables","pChecked","configureSession","authenticate","Authenticated","checkSession","Configured","deauthenticate","tmpPageSize","tmpDateTimePrecisionMS","tmpSyncDeletedRecords","tmpLogToFile","tmpPostBody","SyncMode","MaxRecordsPerEntity","LogToFile","stopSync","pollSyncStatus","stopPolling","renderSyncProgress","Running","Stopping","tmpHasErrors","tmpHasPartial","tmpNames","fetchSyncReport","renderSyncReport","pReport","tmpCardsContainer","tmpOutcomeClass","Outcome","tmpOutcomeColor","Partial","Stopped","tmpDurationSec","RunTimestamps","DurationSeconds","tmpDurationStr","tmpTotalSynced","Summary","tmpTotalRecords","Complete","tmpAnomalyContainer","Anomalies","tmpAnomaly","tmpTypeColor","tmpTopContainer","tmpTopCount","tmpTable","tmpDur","tmpRecs","tmpStatusColor","downloadReport","Date","toISOString","slice","copyReport","tmpSyncing","fRenderRow","pName","pTable","tmpStatusBadge","tmpDetails","Skipped","tmpShowCount","tmpSelect","tmpCurrentValue","tmpDeployedTables","tmpOpt","loadTableData","tmpLimit","renderDataTable","pRows","tmpColumns","tmpDisplay"],"mappings":"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","file":"data-cloner.min.js","sourcesContent":["(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.dataCloner = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\nmodule.exports={\n \"name\": \"fable-serviceproviderbase\",\n \"version\": \"3.0.19\",\n \"description\": \"Simple base classes for fable services.\",\n \"main\": \"source/Fable-ServiceProviderBase.js\",\n \"scripts\": {\n \"start\": \"node source/Fable-ServiceProviderBase.js\",\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"types\": \"tsc -p ./tsconfig.build.json\",\n \"check\": \"tsc -p . --noEmit\"\n },\n \"types\": \"types/source/Fable-ServiceProviderBase.d.ts\",\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/stevenvelozo/fable-serviceproviderbase.git\"\n },\n \"keywords\": [\n \"entity\",\n \"behavior\"\n ],\n \"author\": \"Steven Velozo <steven@velozo.com> (http://velozo.com/)\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/fable-serviceproviderbase/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/fable-serviceproviderbase\",\n \"devDependencies\": {\n \"@types/mocha\": \"^10.0.10\",\n \"fable\": \"^3.1.62\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n }\n}\n\n},{}],2:[function(require,module,exports){\n/**\n* Fable Service Base\n* @author <steven@velozo.com>\n*/\n\nconst libPackage = require('../package.json');\n\nclass FableServiceProviderBase\n{\n\t/**\n\t * The constructor can be used in two ways:\n\t * 1) With a fable, options object and service hash (the options object and service hash are optional)a\n\t * 2) With an object or nothing as the first parameter, where it will be treated as the options object\n\t *\n\t * @param {import('fable')|Record<string, any>} [pFable] - (optional) The fable instance, or the options object if there is no fable\n\t * @param {Record<string, any>|string} [pOptions] - (optional) The options object, or the service hash if there is no fable\n\t * @param {string} [pServiceHash] - (optional) The service hash to identify this service instance\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t/** @type {import('fable')} */\n\t\tthis.fable;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.options;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.services;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.servicesMap;\n\n\t\t// Check if a fable was passed in; connect it if so\n\t\tif ((typeof(pFable) === 'object') && pFable.isFable)\n\t\t{\n\t\t\tthis.connectFable(pFable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.fable = false;\n\t\t}\n\n\t\t// Initialize the services map if it wasn't passed in\n\t\t/** @type {Record<string, any>} */\n\t\tthis._PackageFableServiceProvider = libPackage;\n\n\t\t// initialize options and UUID based on whether the fable was passed in or not.\n\t\tif (this.fable)\n\t\t{\n\t\t\tthis.UUID = pFable.getUUID();\n\t\t\tthis.options = (typeof(pOptions) === 'object') ? pOptions\n\t\t\t\t\t\t\t: {};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// With no fable, check to see if there was an object passed into either of the first two\n\t\t\t// Parameters, and if so, treat it as the options object\n\t\t\tthis.options = ((typeof(pFable) === 'object') && !pFable.isFable) ? pFable\n\t\t\t\t\t\t\t: (typeof(pOptions) === 'object') ? pOptions\n\t\t\t\t\t\t\t: {};\n\t\t\tthis.UUID = `CORE-SVC-${Math.floor((Math.random() * (99999 - 10000)) + 10000)}`\n\t\t}\n\n\t\t// It's expected that the deriving class will set this\n\t\tthis.serviceType = `Unknown-${this.UUID}`;\n\n\t\t// The service hash is used to identify the specific instantiation of the service in the services map\n\t\tthis.Hash = (typeof(pServiceHash) === 'string') ? pServiceHash \n\t\t\t\t\t: (!this.fable && (typeof(pOptions) === 'string')) ? pOptions\n\t\t\t\t\t: `${this.UUID}`;\n\t}\n\n\t/**\n\t * @param {import('fable')} pFable\n\t */\n\tconnectFable(pFable)\n\t{\n\t\tif ((typeof(pFable) !== 'object') || (!pFable.isFable))\n\t\t{\n\t\t\tlet tmpErrorMessage = `Fable Service Provider Base: Cannot connect to Fable, invalid Fable object passed in. The pFable parameter was a [${typeof(pFable)}].}`;\n\t\t\tconsole.log(tmpErrorMessage);\n\t\t\treturn new Error(tmpErrorMessage);\n\t\t}\n\n\t\tif (!this.fable)\n\t\t{\n\t\t\tthis.fable = pFable;\n\t\t}\n\n\t\tif (!this.log)\n\t\t{\n\t\t\tthis.log = this.fable.Logging;\n\t\t}\n\t\tif (!this.services)\n\t\t{\n\t\t\tthis.services = this.fable.services;\n\t\t}\n\n\t\tif (!this.servicesMap)\n\t\t{\n\t\t\tthis.servicesMap = this.fable.servicesMap;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tstatic isFableService = true;\n}\n\nmodule.exports = FableServiceProviderBase;\n\n// This is left here in case we want to go back to having different code/base class for \"core\" services\nmodule.exports.CoreServiceProviderBase = FableServiceProviderBase;\n\n},{\"../package.json\":1}],3:[function(require,module,exports){\nmodule.exports={\n \"name\": \"pict-application\",\n \"version\": \"1.0.33\",\n \"description\": \"Application base class for a pict view-based application\",\n \"main\": \"source/Pict-Application.js\",\n \"scripts\": {\n \"test\": \"npx quack test\",\n \"start\": \"node source/Pict-Application.js\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-application-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-application-dev -p 30001:8080 -p 38086:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-application\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-application-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-application-dev /bin/bash\",\n \"tests\": \"npx quack test -g\",\n \"lint\": \"eslint source/**\",\n \"types\": \"tsc -p .\"\n },\n \"types\": \"types/source/Pict-Application.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-application.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-application/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-application#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.28.0\",\n \"browser-env\": \"^3.3.0\",\n \"eslint\": \"^9.28.0\",\n \"pict\": \"^1.0.348\",\n \"pict-provider\": \"^1.0.10\",\n \"pict-view\": \"^1.0.66\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"dependencies\": {\n \"fable-serviceproviderbase\": \"^3.0.19\"\n }\n}\n\n},{}],4:[function(require,module,exports){\nconst libFableServiceBase = require('fable-serviceproviderbase')\n\nconst libPackage = require('../package.json');\n\nconst defaultPictSettings = (\n\t{\n\t\tName: 'DefaultPictApplication',\n\n\t\t// The main \"viewport\" is the view that is used to host our application\n\t\tMainViewportViewIdentifier: 'Default-View',\n\t\tMainViewportRenderableHash: false,\n\t\tMainViewportDestinationAddress: false,\n\t\tMainViewportDefaultDataAddress: false,\n\n\t\t// Whether or not we should automatically render the main viewport and other autorender views after we initialize the pict application\n\t\tAutoSolveAfterInitialize: true,\n\t\tAutoRenderMainViewportViewAfterInitialize: true,\n\t\tAutoRenderViewsAfterInitialize: false,\n\t\tAutoLoginAfterInitialize: false,\n\t\tAutoLoadDataAfterLogin: false,\n\n\t\tConfigurationOnlyViews: [],\n\n\t\tManifests: {},\n\t\t// The prefix to prepend on all template destination hashes\n\t\tIdentifierAddressPrefix: 'PICT-'\n\t});\n\n/**\n * Base class for pict applications.\n */\nclass PictApplication extends libFableServiceBase\n{\n\t/**\n\t * @param {import('fable')} pFable\n\t * @param {Record<string, any>} [pOptions]\n\t * @param {string} [pServiceHash]\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tlet tmpCarryOverConfiguration = (typeof(pFable.settings.PictApplicationConfiguration) === 'object') ? pFable.settings.PictApplicationConfiguration : {};\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictSettings)), tmpCarryOverConfiguration, pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\t/** @type {any} */\n\t\tthis.options;\n\t\t/** @type {any} */\n\t\tthis.log;\n\t\t/** @type {import('pict') & import('fable')} */\n\t\tthis.fable;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {string} */\n\t\tthis.Hash;\n\t\t/**\n\t\t * @type {{ [key: string]: any }}\n\t\t */\n\t\tthis.servicesMap;\n\n\t\tthis.serviceType = 'PictApplication';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\n\t\t// Convenience and consistency naming\n\t\tthis.pict = this.fable;\n\t\t// Wire in the essential Pict state\n\t\t/** @type {Record<string, any>} */\n\t\tthis.AppData = this.fable.AppData;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.Bundle = this.fable.Bundle;\n\n\t\t/** @type {number} */\n\t\tthis.initializeTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastSolvedTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastLoginTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastMarshalFromViewsTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastMarshalToViewsTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastAutoRenderTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastLoadDataTimestamp;\n\n\t\t// Load all the manifests for the application\n\t\tlet tmpManifestKeys = Object.keys(this.options.Manifests);\n\t\tif (tmpManifestKeys.length > 0)\n\t\t{\n\t\t\tfor (let i = 0; i < tmpManifestKeys.length; i++)\n\t\t\t{\n\t\t\t\t// Load each manifest\n\t\t\t\tlet tmpManifestKey = tmpManifestKeys[i];\n\t\t\t\tthis.fable.instantiateServiceProvider('Manifest', this.options.Manifests[tmpManifestKey], tmpManifestKey);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Solve All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonPreSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onPreSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonPreSolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeSolveAsync(fCallback)\n\t{\n\t\tthis.onBeforeSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonSolveAsync(fCallback)\n\t{\n\t\tthis.onSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tsolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing solve() function...`)\n\t\t}\n\n\t\t// Walk through any loaded providers and solve them as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSolve.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpProvidersToSolve.length; i++)\n\t\t{\n\t\t\ttmpProvidersToSolve[i].solve(tmpProvidersToSolve[i]);\n\t\t}\n\n\t\tthis.onBeforeSolve();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t{\n\t\t\t\ttmpViewsToSolve.push(tmpView);\n\t\t\t}\n\t\t}\n\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpViewsToSolve.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\tfor (let i = 0; i < tmpViewsToSolve.length; i++)\n\t\t{\n\t\t\ttmpViewsToSolve[i].solve();\n\t\t}\n\t\tthis.onSolve();\n\t\tthis.onAfterSolve();\n\t\tthis.lastSolvedTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));\n\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\t\t// Walk through any loaded providers and solve them as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSolve.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpProvidersToSolve.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvidersToSolve[i].solveAsync.bind(tmpProvidersToSolve[i]));\n\t\t}\n\n\t\t// Walk through any loaded views and solve them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpViewsToSolve.push(tmpView);\n\t\t\t}\n\t\t}\n\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpViewsToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpViewsToSolve.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToSolve[i].solveAsync.bind(tmpViewsToSolve[i]));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSolvedTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterSolveAsync(fCallback)\n\t{\n\t\tthis.onAfterSolve();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application Login */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tloginAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeLoginAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onLoginAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterLoginAsync.bind(this));\n\n\t\t// check and see if we should automatically trigger a data load\n\t\tif (this.options.AutoLoadDataAfterLogin)\n\t\t{\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tif (!this.isLoggedIn())\n\t\t\t\t{\n\t\t\t\t\treturn fNext();\n\t\t\t\t}\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto loading data after login...`);\n\t\t\t\t}\n\t\t\t\t//TODO: should data load errors funnel here? this creates a weird coupling between login and data load callbacks\n\t\t\t\tthis.loadDataAsync((pError) =>\n\t\t\t\t{\n\t\t\t\t\tfNext(pError);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastLoginTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Check if the application state is logged in. Defaults to true. Override this method in your application based on login requirements.\n\t *\n\t * @return {boolean}\n\t */\n\tisLoggedIn()\n\t{\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application LoadData */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tloadDataAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeLoadDataAsync.bind(this));\n\n\t\t// Walk through any loaded providers and load their data as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToLoadData = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoLoadDataWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToLoadData.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToLoadData.sort((a, b) => { return a.options.AutoLoadDataOrdinal - b.options.AutoLoadDataOrdinal; });\n\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onBeforeLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onLoadDataAsync.bind(this));\n\n\t\t//TODO: think about ways to parallelize these\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onAfterLoadDataAsync.bind(this));\n\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onAfterLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t/** @param {Error} [pError] */\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastLoadDataTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application SaveData */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tsaveDataAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSaveDataAsync.bind(this));\n\n\t\t// Walk through any loaded providers and load their data as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSaveData = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSaveDataWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSaveData.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSaveData.sort((a, b) => { return a.options.AutoSaveDataOrdinal - b.options.AutoSaveDataOrdinal; });\n\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onBeforeSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onSaveDataAsync.bind(this));\n\n\t\t//TODO: think about ways to parallelize these\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onAfterSaveDataAsync.bind(this));\n\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onAfterSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t/** @param {Error} [pError] */\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSaveDataTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialize Application */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\n\t\t\tif ('ConfigurationOnlyViews' in this.options)\n\t\t\t{\n\t\t\t\t// Load all the configuration only views\n\t\t\t\tfor (let i = 0; i < this.options.ConfigurationOnlyViews.length; i++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpViewIdentifier = (typeof(this.options.ConfigurationOnlyViews[i].ViewIdentifier) === 'undefined') ? `AutoView-${this.fable.getUUID()}`\n\t\t\t\t\t\t\t\t\t\t\t: this.options.ConfigurationOnlyViews[i].ViewIdentifier;\n\t\t\t\t\tthis.log.info(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} adding configuration only view: ${tmpViewIdentifier}`);\n\t\t\t\t\tthis.pict.addView(tmpViewIdentifier, this.options.ConfigurationOnlyViews[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.onInitialize();\n\n\t\t\t// Walk through any loaded providers and initialize them as well.\n\t\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\t\tlet tmpProvidersToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\t\tif (tmpProvider.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpProvidersToInitialize.push(tmpProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpProvidersToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpProvidersToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpProvidersToInitialize[i].initialize();\n\t\t\t}\n\n\t\t\t// Now walk through any loaded views and initialize them as well.\n\t\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t\tlet tmpViewsToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpViewsToInitialize.push(tmpView);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpViewsToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpViewsToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpViewsToInitialize[i].initialize();\n\t\t\t}\n\n\t\t\tthis.onAfterInitialize();\n\t\t\tif (this.options.AutoSolveAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto solving after initialization...`);\n\t\t\t\t}\n\t\t\t\t// Solve the template synchronously\n\t\t\t\tthis.solve();\n\t\t\t}\n\t\t\t// Now check and see if we should automatically render as well\n\t\t\tif (this.options.AutoRenderMainViewportViewAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto rendering after initialization...`);\n\t\t\t\t}\n\t\t\t\t// Render the template synchronously\n\t\t\t\tthis.render();\n\t\t\t}\n\t\t\tthis.initializeTimestamp = this.fable.log.getTimeStamp();\n\t\t\tthis.onCompletionOfInitialize();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync:`);\n\t\t}\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 3)\n\t\t\t{\n\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning initialization...`);\n\t\t\t}\n\n\t\t\tif ('ConfigurationOnlyViews' in this.options)\n\t\t\t{\n\t\t\t\t// Load all the configuration only views\n\t\t\t\tfor (let i = 0; i < this.options.ConfigurationOnlyViews.length; i++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpViewIdentifier = (typeof(this.options.ConfigurationOnlyViews[i].ViewIdentifier) === 'undefined') ? `AutoView-${this.fable.getUUID()}`\n\t\t\t\t\t\t\t\t\t\t\t: this.options.ConfigurationOnlyViews[i].ViewIdentifier;\n\t\t\t\t\tthis.log.info(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} adding configuration only view: ${tmpViewIdentifier}`);\n\t\t\t\t\tthis.pict.addView(tmpViewIdentifier, this.options.ConfigurationOnlyViews[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\n\t\t\t// Walk through any loaded providers and solve them as well.\n\t\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\t\tlet tmpProvidersToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\t\tif (tmpProvider.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpProvidersToInitialize.push(tmpProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpProvidersToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpProvidersToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpAnticipate.anticipate(tmpProvidersToInitialize[i].initializeAsync.bind(tmpProvidersToInitialize[i]));\n\t\t\t}\n\n\t\t\t// Now walk through any loaded views and initialize them as well.\n\t\t\t// TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.\n\t\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t\tlet tmpViewsToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpViewsToInitialize.push(tmpView);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the views by their priority\n\t\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\t\ttmpViewsToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpViewsToInitialize.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = tmpViewsToInitialize[i];\n\t\t\t\ttmpAnticipate.anticipate(tmpView.initializeAsync.bind(tmpView));\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\tif (this.options.AutoLoginAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto login (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.loginAsync.bind(this));\n\t\t\t}\n\n\t\t\tif (this.options.AutoSolveAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto solving (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.solveAsync.bind(this));\n\t\t\t}\n\n\t\t\tif (this.options.AutoRenderMainViewportViewAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto rendering (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.renderMainViewportAsync.bind(this));\n\t\t\t}\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync Error: ${pError.message || pError}`, { stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\tthis.initializeTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn tmpCallback();\n\t\t\t\t});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn this.onCompletionOfInitializeAsync(tmpCallback);\n\t\t}\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonCompletionOfInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onCompletionOfInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonCompletionOfInitializeAsync(fCallback)\n\t{\n\t\tthis.onCompletionOfInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal Data From All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tmarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing marshalFromViews() function...`)\n\t\t}\n\t\tthis.onBeforeMarshalFromViews();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalFromViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalFromViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalFromViews.length; i++)\n\t\t{\n\t\t\ttmpViewsToMarshalFromViews[i].marshalFromView();\n\t\t}\n\t\tthis.onMarshalFromViews();\n\t\tthis.onAfterMarshalFromViews();\n\t\tthis.lastMarshalFromViewsTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tmarshalFromViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalFromViewsAsync.bind(this));\n\t\t// Walk through any loaded views and marshalFromViews them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalFromViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalFromViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalFromViews.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToMarshalFromViews[i].marshalFromViewAsync.bind(tmpViewsToMarshalFromViews[i]));\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onMarshalFromViewsAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalFromViewsAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalFromViewsTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal Data To All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tmarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing marshalToViews() function...`)\n\t\t}\n\t\tthis.onBeforeMarshalToViews();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalToViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalToViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalToViews.length; i++)\n\t\t{\n\t\t\ttmpViewsToMarshalToViews[i].marshalToView();\n\t\t}\n\t\tthis.onMarshalToViews();\n\t\tthis.onAfterMarshalToViews();\n\t\tthis.lastMarshalToViewsTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tmarshalToViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalToViewsAsync.bind(this));\n\t\t// Walk through any loaded views and marshalToViews them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalToViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalToViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalToViews.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToMarshalToViews[i].marshalToViewAsync.bind(tmpViewsToMarshalToViews[i]));\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onMarshalToViewsAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalToViewsAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalToViewsTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Render View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeRenderAsync(fCallback)\n\t{\n\t\tthis.onBeforeRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {string} [pViewIdentifier] - The hash of the view to render. By default, the main viewport view is rendered.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string} [pTemplateDataAddress] - The address where the data for the template is stored.\n\t *\n\t * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?\n\t */\n\trender(pViewIdentifier, pRenderableHash, pRenderDestinationAddress, pTemplateDataAddress)\n\t{\n\t\tlet tmpViewIdentifier = (typeof(pViewIdentifier) !== 'string') ? this.options.MainViewportViewIdentifier : pViewIdentifier;\n\t\tlet tmpRenderableHash = (typeof(pRenderableHash) !== 'string') ? this.options.MainViewportRenderableHash : pRenderableHash;\n\t\tlet tmpRenderDestinationAddress = (typeof(pRenderDestinationAddress) !== 'string') ? this.options.MainViewportDestinationAddress : pRenderDestinationAddress;\n\t\tlet tmpTemplateDataAddress = (typeof(pTemplateDataAddress) !== 'string') ? this.options.MainViewportDefaultDataAddress : pTemplateDataAddress;\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} VIEW Renderable[${tmpRenderableHash}] Destination[${tmpRenderDestinationAddress}] TemplateDataAddress[${tmpTemplateDataAddress}] render:`);\n\t\t}\n\n\t\tthis.onBeforeRender();\n\n\t\t// Now get the view (by hash) from the loaded views\n\t\tlet tmpView = (typeof (tmpViewIdentifier) === 'string') ? this.servicesMap.PictView[tmpViewIdentifier] : false;\n\t\tif (!tmpView)\n\t\t{\n\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} could not render from View ${tmpViewIdentifier} because it is not a valid view.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.onRender();\n\n\t\ttmpView.render(tmpRenderableHash, tmpRenderDestinationAddress, tmpTemplateDataAddress);\n\n\t\tthis.onAfterRender();\n\n\t\treturn true;\n\t}\n\t/**\n\t * @return {boolean}\n\t */\n\tonRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonRenderAsync(fCallback)\n\t{\n\t\tthis.onRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {string|((error?: Error) => void)} pViewIdentifier - The hash of the view to render. By default, the main viewport view is rendered. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pRenderableHash] - The hash of the renderable to render. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pRenderDestinationAddress] - The address where the renderable will be rendered. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pTemplateDataAddress] - The address where the data for the template is stored. (or the callback)\n\t * @param {(error?: Error) => void} [fCallback] - The callback, if all other parameters are provided.\n\t *\n\t * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?\n\t */\n\trenderAsync(pViewIdentifier, pRenderableHash, pRenderDestinationAddress, pTemplateDataAddress, fCallback)\n\t{\n\t\tlet tmpViewIdentifier = (typeof(pViewIdentifier) !== 'string') ? this.options.MainViewportViewIdentifier : pViewIdentifier;\n\t\tlet tmpRenderableHash = (typeof(pRenderableHash) !== 'string') ? this.options.MainViewportRenderableHash : pRenderableHash;\n\t\tlet tmpRenderDestinationAddress = (typeof(pRenderDestinationAddress) !== 'string') ? this.options.MainViewportDestinationAddress : pRenderDestinationAddress;\n\t\tlet tmpTemplateDataAddress = (typeof(pTemplateDataAddress) !== 'string') ? this.options.MainViewportDefaultDataAddress : pTemplateDataAddress;\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateDataAddress) === 'function') ? pTemplateDataAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\t(typeof(pViewIdentifier) === 'function') ? pViewIdentifier :\n\t\t\t\t\t\t\tfalse;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} VIEW Renderable[${tmpRenderableHash}] Destination[${tmpRenderDestinationAddress}] TemplateDataAddress[${tmpTemplateDataAddress}] renderAsync:`);\n\t\t}\n\n\t\tlet tmpRenderAnticipate = this.fable.newAnticipate();\n\n\t\ttmpRenderAnticipate.anticipate(this.onBeforeRenderAsync.bind(this));\n\n\t\tlet tmpView = (typeof (tmpViewIdentifier) === 'string') ? this.servicesMap.PictView[tmpViewIdentifier] : false;\n\t\tif (!tmpView)\n\t\t{\n\t\t\tlet tmpErrorMessage = `PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} could not asynchronously render from View ${tmpViewIdentifier} because it is not a valid view.`;\n\t\t\tif (this.pict.LogNoisiness > 3)\n\t\t\t{\n\t\t\t\tthis.log.error(tmpErrorMessage);\n\t\t\t}\n\t\t\treturn tmpCallback(new Error(tmpErrorMessage));\n\t\t}\n\n\t\ttmpRenderAnticipate.anticipate(this.onRenderAsync.bind(this));\n\n\t\ttmpRenderAnticipate.anticipate(\n\t\t\t(fNext) =>\n\t\t\t{\n\t\t\t\ttmpView.renderAsync.call(tmpView, tmpRenderableHash, tmpRenderDestinationAddress, tmpTemplateDataAddress, fNext);\n\t\t\t});\n\n\t\ttmpRenderAnticipate.anticipate(this.onAfterRenderAsync.bind(this));\n\n\t\treturn tmpRenderAnticipate.wait(tmpCallback);\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterRenderAsync(fCallback)\n\t{\n\t\tthis.onAfterRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\trenderMainViewport()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderMainViewport:`);\n\t\t}\n\n\t\treturn this.render();\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\trenderMainViewportAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderMainViewportAsync:`);\n\t\t}\n\n\t\treturn this.renderAsync(fCallback);\n\t}\n\t/**\n\t * @return {void}\n\t */\n\trenderAutoViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning renderAutoViews...`);\n\t\t}\n\t\t// Now walk through any loaded views and sort them by the AutoRender ordinal\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t// Sort the views by their priority\n\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\ttmpLoadedViews.sort((a, b) =>\n\t\t{\n\t\t\treturn this.pict.views[a].options.AutoRenderOrdinal - this.pict.views[b].options.AutoRenderOrdinal;\n\t\t});\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoRender)\n\t\t\t{\n\t\t\t\ttmpView.render();\n\t\t\t}\n\t\t}\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync complete.`);\n\t\t}\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\trenderAutoViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\tfalse;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning renderAutoViewsAsync...`);\n\t\t}\n\n\t\t// Now walk through any loaded views and sort them by the AutoRender ordinal\n\t\t// TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t// Sort the views by their priority\n\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\ttmpLoadedViews.sort((a, b) =>\n\t\t{\n\t\t\treturn this.pict.views[a].options.AutoRenderOrdinal - this.pict.views[b].options.AutoRenderOrdinal;\n\t\t});\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoRender)\n\t\t\t{\n\t\t\t\ttmpAnticipate.anticipate(tmpView.renderAsync.bind(tmpView));\n\t\t\t}\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tthis.lastAutoRenderTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync complete.`);\n\t\t\t\t}\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tget isPictApplication()\n\t{\n\t\treturn true;\n\t}\n}\n\nmodule.exports = PictApplication;\n\n},{\"../package.json\":3,\"fable-serviceproviderbase\":2}],5:[function(require,module,exports){\nmodule.exports={\n \"name\": \"pict-provider\",\n \"version\": \"1.0.12\",\n \"description\": \"Pict Provider Base Class\",\n \"main\": \"source/Pict-Provider.js\",\n \"scripts\": {\n \"start\": \"node source/Pict-Provider.js\",\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-provider-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-provider-dev -p 24125:8080 -p 30027:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-provider\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-provider-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-provider-dev /bin/bash\",\n \"lint\": \"eslint source/**\",\n \"types\": \"tsc -p .\"\n },\n \"types\": \"types/source/Pict-Provider.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-provider.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-provider/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-provider#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.1\",\n \"eslint\": \"^9.39.1\",\n \"pict\": \"^1.0.351\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"dependencies\": {\n \"fable-serviceproviderbase\": \"^3.0.19\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n }\n}\n\n},{}],6:[function(require,module,exports){\nconst libFableServiceBase = require('fable-serviceproviderbase');\n\nconst libPackage = require('../package.json');\n\nconst defaultPictProviderSettings = (\n\t{\n\t\tProviderIdentifier: false,\n\n\t\t// If this is set to true, when the App initializes this will.\n\t\t// After the App initializes, initialize will be called as soon as it's added.\n\t\tAutoInitialize: true,\n\t\tAutoInitializeOrdinal: 0,\n\n\t\tAutoLoadDataWithApp: true,\n\t\tAutoLoadDataOrdinal: 0,\n\n\t\tAutoSolveWithApp: true,\n\t\tAutoSolveOrdinal: 0,\n\n\t\tManifests: {},\n\n\t\tTemplates: []\n\t});\n\nclass PictProvider extends libFableServiceBase\n{\n\t/**\n\t * @param {import('fable')} pFable - The Fable instance.\n\t * @param {Record<string, any>} [pOptions] - The options for the provider.\n\t * @param {string} [pServiceHash] - The service hash for the provider.\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t// Intersect default options, parent constructor, service information\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictProviderSettings)), pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\t/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */\n\t\tthis.fable;\n\t\t/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */\n\t\tthis.pict;\n\t\t/** @type {any} */\n\t\tthis.log;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.options;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {string} */\n\t\tthis.Hash;\n\n\t\tif (!this.options.ProviderIdentifier)\n\t\t{\n\t\t\tthis.options.ProviderIdentifier = `AutoProviderID-${this.fable.getUUID()}`;\n\t\t}\n\n\t\tthis.serviceType = 'PictProvider';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\n\t\t// Convenience and consistency naming\n\t\tthis.pict = this.fable;\n\n\t\t// Wire in the essential Pict application state\n\t\t/** @type {Record<string, any>} */\n\t\tthis.AppData = this.pict.AppData;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.Bundle = this.pict.Bundle;\n\n\t\tthis.initializeTimestamp = false;\n\t\tthis.lastSolvedTimestamp = false;\n\n\t\tfor (let i = 0; i < this.options.Templates.length; i++)\n\t\t{\n\t\t\tlet tmpDefaultTemplate = this.options.Templates[i];\n\n\t\t\tif (!tmpDefaultTemplate.hasOwnProperty('Postfix') || !tmpDefaultTemplate.hasOwnProperty('Template'))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} could not load Default Template ${i} in the options array.`, tmpDefaultTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpDefaultTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpDefaultTemplate.Source = `PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix, tmpDefaultTemplate.Postfix, tmpDefaultTemplate.Template, tmpDefaultTemplate.Source);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialization */\n\t/* -------------------------------------------------------------------------- */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-pinitialization.\n\t *\n\t * @return {void}\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\tonInitialize()\n\t{\n\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow PROVIDER [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\t\t\tthis.onInitialize();\n\t\t\tthis.onAfterInitialize();\n\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow PROVIDER [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initializeAsync:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.info(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} beginning initialization...`);\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialization failed: ${pError.message || pError}`, { Stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\telse if (this.pict.LogNoisiness > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.info(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fCallback();\n\t\t\t\t})\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn fCallback();\n\t\t}\n\t}\n\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\tonPreRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onPreRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-render.\n\t *\n\t * @return {void}\n\t */\n\tonPreRenderAsync(fCallback)\n\t{\n\t\tthis.onPreRender();\n\t\treturn fCallback();\n\t}\n\n\trender()\n\t{\n\t\treturn this.onPreRender();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after render.\n\t *\n\t * @return {void}\n\t */\n\trenderAsync(fCallback)\n\t{\n\t\tthis.onPreRender();\n\t\treturn fCallback();\n\t}\n\n\tonPreSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onPreSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-solve.\n\t *\n\t * @return {void}\n\t */\n\tonPreSolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\tsolve()\n\t{\n\t\treturn this.onPreSolve();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after solve.\n\t *\n\t * @return {void}\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.\n\t */\n\tonBeforeLoadDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Hook to allow the provider to load data during application data load.\n\t *\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.\n\t */\n\tonLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.\n\t */\n\tonAfterLoadDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.\n\t *\n\t * @return {void}\n\t */\n\tonBeforeSaveDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Hook to allow the provider to load data during application data load.\n\t *\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.\n\t *\n\t * @return {void}\n\t */\n\tonSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.\n\t *\n\t * @return {void}\n\t */\n\tonAfterSaveDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n}\n\nmodule.exports = PictProvider;\n\n},{\"../package.json\":5,\"fable-serviceproviderbase\":2}],7:[function(require,module,exports){\nmodule.exports = (\n{\n\t\"RenderOnLoad\": true,\n\n\t\"DefaultRenderable\": \"Histogram-Wrap\",\n\t\"DefaultDestinationAddress\": \"#Histogram-Container-Div\",\n\n\t\"Templates\":\n\t[\n\t\t{\n\t\t\t\"Hash\": \"Histogram-Container\",\n\t\t\t\"Template\": \"<!-- Histogram Container Rendering Soon -->\"\n\t\t}\n\t],\n\n\t\"Renderables\":\n\t[\n\t\t{\n\t\t\t\"RenderableHash\": \"Histogram-Wrap\",\n\t\t\t\"TemplateHash\": \"Histogram-Container\",\n\t\t\t\"DestinationAddress\": \"#Histogram-Container-Div\"\n\t\t}\n\t],\n\n\t\"TargetElementAddress\": \"#Histogram-Container-Div\",\n\n\t// --- Data Configuration ---\n\n\t// Address in AppData (or other Pict address space) for the histogram bins\n\t// Expected format: Array of objects with at least { Label, Value } properties\n\t// e.g. [{ Label: \"2020\", Value: 15 }, { Label: \"2021\", Value: 42 }]\n\t\"DataAddress\": false,\n\n\t// Alternatively, provide bins directly (used if DataAddress is not set)\n\t\"Bins\": [],\n\n\t// Property names within each bin object\n\t\"LabelProperty\": \"Label\",\n\t\"ValueProperty\": \"Value\",\n\n\t// --- Layout Configuration ---\n\n\t// \"vertical\" = bars grow upward; \"horizontal\" = bars grow rightward\n\t\"Orientation\": \"vertical\",\n\n\t// The rendering mode: \"browser\", \"consoleui\", or \"cli\"\n\t// \"browser\" renders HTML/CSS/SVG; \"consoleui\" renders via blessed widgets;\n\t// \"cli\" renders ANSI text to stdout\n\t\"RenderMode\": \"browser\",\n\n\t// Maximum height in pixels (browser vertical) or characters (cli/consoleui)\n\t\"MaxBarSize\": 200,\n\n\t// Bar thickness in pixels (browser) or characters (cli/consoleui)\n\t\"BarThickness\": 30,\n\n\t// Gap between bars in pixels (browser) or characters (cli/consoleui)\n\t\"BarGap\": 4,\n\n\t// When true, bar groups expand to fill the container width (vertical) or\n\t// height (horizontal) using CSS flex-grow instead of a fixed BarThickness.\n\t// Labels and values overflow their column so they remain readable even when\n\t// bars are very narrow. Best suited for time-series or dense histograms.\n\t\"FillContainer\": false,\n\n\t// Whether to show value labels on/above bars\n\t\"ShowValues\": true,\n\n\t// Whether to show bin labels (x-axis for vertical, y-axis for horizontal)\n\t\"ShowLabels\": true,\n\n\t// In FillContainer mode, controls label density in the separate label row.\n\t// 0 = auto-compute (space labels approximately 80px apart based on container\n\t// width), N > 0 = show a label every N bars starting from index 0.\n\t// Ignored when FillContainer is false (every bar shows its own label).\n\t\"LabelInterval\": 0,\n\n\t// Color of the bars (CSS color for browser, ANSI color name for cli/consoleui)\n\t\"BarColor\": \"#4A90D9\",\n\n\t// Color of selected bars\n\t\"SelectedBarColor\": \"#2ECC71\",\n\n\t// Color of bars in the selection range\n\t\"SelectionRangeColor\": \"#85C1E9\",\n\n\t// --- Selection Configuration ---\n\n\t// Enable selection mode\n\t\"Selectable\": false,\n\n\t// Selection mode: \"single\", \"multiple\", \"range\"\n\t// \"single\" - click to select one bar\n\t// \"multiple\" - click to toggle individual bars\n\t// \"range\" - drag sliders to select a contiguous range of bins\n\t\"SelectionMode\": \"range\",\n\n\t// Address in AppData to write selection state\n\t// Will contain { SelectedIndices: [], RangeStart: N, RangeEnd: N } or similar\n\t\"SelectionDataAddress\": false,\n\n\t// Initial selection (array of indices or { Start, End } for range mode)\n\t\"InitialSelection\": null,\n\n\t// --- CLI/ConsoleUI Configuration ---\n\n\t// Characters used for rendering in text mode\n\t\"BarCharacter\": \"\\u2588\",\n\t\"BarPartialCharacters\": [\" \", \"\\u2581\", \"\\u2582\", \"\\u2583\", \"\\u2584\", \"\\u2585\", \"\\u2586\", \"\\u2587\", \"\\u2588\"],\n\t\"EmptyCharacter\": \" \",\n\t\"SliderCharacter\": \"\\u2502\",\n\t\"SliderHandleCharacter\": \"\\u25C6\",\n\n\t// Width of the histogram in characters (cli/consoleui)\n\t\"TextWidth\": 60,\n\n\t// Height of the histogram in characters (cli/consoleui vertical)\n\t\"TextHeight\": 15,\n\n\t// --- CSS ---\n\t\"CSS\": `.pict-histogram-container\n{\n\tdisplay: inline-block;\n\tposition: relative;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n\tfont-size: 12px;\n\tuser-select: none;\n}\n.pict-histogram-chart\n{\n\tdisplay: flex;\n\talign-items: flex-end;\n\tposition: relative;\n}\n.pict-histogram-container.pict-histogram-horizontal\n{\n\tdisplay: inline-flex;\n\tflex-direction: row;\n\talign-items: stretch;\n}\n.pict-histogram-chart.pict-histogram-horizontal\n{\n\tflex-direction: column;\n\talign-items: flex-start;\n}\n.pict-histogram-bar-group\n{\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tcursor: default;\n\tflex-shrink: 0;\n}\n.pict-histogram-horizontal .pict-histogram-bar-group\n{\n\tflex-direction: row;\n\talign-items: center;\n}\n.pict-histogram-bar\n{\n\ttransition: background-color 0.15s ease, height 0.2s ease, width 0.2s ease;\n\tborder-radius: 2px 2px 0 0;\n\tmin-width: 1px;\n\tmin-height: 1px;\n}\n.pict-histogram-horizontal .pict-histogram-bar\n{\n\tborder-radius: 0 2px 2px 0;\n}\n.pict-histogram-bar.pict-histogram-selectable\n{\n\tcursor: pointer;\n}\n.pict-histogram-bar.pict-histogram-selectable:hover\n{\n\topacity: 0.8;\n}\n.pict-histogram-bar.pict-histogram-selected\n{\n\tbox-shadow: 0 0 0 2px rgba(46, 204, 113, 0.4);\n}\n.pict-histogram-bar.pict-histogram-in-range\n{\n\topacity: 0.9;\n}\n.pict-histogram-value-label\n{\n\ttext-align: center;\n\tcolor: #666;\n\tfont-size: 11px;\n\tpadding: 2px 0;\n\twhite-space: nowrap;\n}\n.pict-histogram-horizontal .pict-histogram-value-label\n{\n\tpadding: 0 4px;\n}\n.pict-histogram-bin-label\n{\n\ttext-align: center;\n\tcolor: #333;\n\tfont-size: 11px;\n\tpadding: 4px 2px 0 2px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n.pict-histogram-horizontal .pict-histogram-bin-label\n{\n\tpadding: 0 4px 0 0;\n\ttext-align: right;\n\tmin-width: 40px;\n}\n.pict-histogram-range-slider-container\n{\n\tposition: relative;\n\twidth: 100%;\n\theight: 24px;\n\tmargin-top: 4px;\n}\n.pict-histogram-horizontal .pict-histogram-range-slider-container\n{\n\twidth: 24px;\n\theight: auto;\n\talign-self: stretch;\n\tmargin-top: 0;\n\tmargin-left: 4px;\n}\n.pict-histogram-range-track\n{\n\tposition: absolute;\n\ttop: 10px;\n\tleft: 0;\n\tright: 0;\n\theight: 4px;\n\tbackground: #E0E0E0;\n\tborder-radius: 2px;\n}\n.pict-histogram-horizontal .pict-histogram-range-track\n{\n\ttop: 0;\n\tleft: 10px;\n\tright: auto;\n\tbottom: 0;\n\twidth: 4px;\n\theight: auto;\n}\n.pict-histogram-range-fill\n{\n\tposition: absolute;\n\ttop: 10px;\n\theight: 4px;\n\tbackground: #4A90D9;\n\tborder-radius: 2px;\n}\n.pict-histogram-horizontal .pict-histogram-range-fill\n{\n\ttop: auto;\n\tleft: 10px;\n\twidth: 4px;\n\theight: auto;\n}\n.pict-histogram-range-handle\n{\n\tposition: absolute;\n\ttop: 4px;\n\twidth: 16px;\n\theight: 16px;\n\tbackground: #fff;\n\tborder: 2px solid #4A90D9;\n\tborder-radius: 50%;\n\tcursor: grab;\n\tz-index: 2;\n\ttransform: translateX(-50%);\n}\n.pict-histogram-horizontal .pict-histogram-range-handle\n{\n\ttop: auto;\n\tleft: 4px;\n\ttransform: translateY(-50%);\n}\n.pict-histogram-range-handle:active\n{\n\tcursor: grabbing;\n\tbackground: #4A90D9;\n}\n.pict-histogram-range-handle:active,\n.pict-histogram-range-handle:focus\n{\n\tbox-shadow: 0 0 0 3px rgba(74, 144, 217, 0.3);\n\toutline: none;\n}\n.pict-histogram-container.pict-histogram-fill\n{\n\tdisplay: block;\n\twidth: 100%;\n}\n.pict-histogram-fill .pict-histogram-chart\n{\n\twidth: 100%;\n}\n.pict-histogram-fill .pict-histogram-bar-group\n{\n\tflex: 1 1 0%;\n\tmin-width: 0;\n}\n.pict-histogram-fill .pict-histogram-bar\n{\n\twidth: 100%;\n}\n.pict-histogram-axis-line\n{\n\twidth: 100%;\n\theight: 1px;\n\tbackground: #ccc;\n}\n.pict-histogram-label-row\n{\n\tdisplay: flex;\n\twidth: 100%;\n}\n.pict-histogram-fill-label\n{\n\tfont-size: 10px;\n\tcolor: #666;\n\ttext-align: center;\n\twhite-space: nowrap;\n\toverflow: visible;\n\tline-height: 16px;\n}\n`\n});\n\n},{}],8:[function(require,module,exports){\n/**\n * Pict Section Histogram\n *\n * A histogram visualization section for the Pict MVC framework.\n *\n * Supports:\n * - Vertical and horizontal orientation\n * - Three render modes: browser (HTML/CSS), consoleui (blessed), cli (ANSI)\n * - Interactive selection: single click, multi-select, or range slider\n * - Data binding via Pict AppData addresses\n *\n * @module pict-section-histogram\n */\n\nconst libPictViewClass = require('pict-view');\nconst _DefaultConfiguration = require('./Pict-Section-Histogram-DefaultConfiguration.js');\n\nconst libRendererBrowser = require('./renderers/Pict-Histogram-Renderer-Browser.js');\nconst libRendererConsoleUI = require('./renderers/Pict-Histogram-Renderer-ConsoleUI.js');\nconst libRendererCLI = require('./renderers/Pict-Histogram-Renderer-CLI.js');\n\nclass PictSectionHistogram extends libPictViewClass\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tlet tmpOptions = Object.assign({}, _DefaultConfiguration, pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\tthis.initialRenderComplete = false;\n\n\t\t// --- Selection State ---\n\n\t\t// Set of selected bin indices (for \"single\" and \"multiple\" modes)\n\t\tthis._selectedIndices = new Set();\n\n\t\t// Range bounds (for \"range\" mode)\n\t\tthis._selectionRangeStart = 0;\n\t\tthis._selectionRangeEnd = 0;\n\n\t\t// Resolve the renderer for the configured mode\n\t\tthis._renderer = this._resolveRenderer();\n\n\t\t// Apply initial selection if provided\n\t\tthis._applyInitialSelection();\n\t}\n\n\t/**\n\t * Set up the initial selection state from options.\n\t */\n\t_applyInitialSelection()\n\t{\n\t\tif (this.options.InitialSelection)\n\t\t{\n\t\t\tthis.setSelection(this.options.InitialSelection);\n\t\t}\n\t\telse if (this.options.Selectable && this.options.SelectionMode === 'range')\n\t\t{\n\t\t\t// Default: select all bins\n\t\t\tlet tmpBins = this.getBins();\n\t\t\tthis._selectionRangeStart = 0;\n\t\t\tthis._selectionRangeEnd = Math.max(0, tmpBins.length - 1);\n\t\t\tthis._syncSelectionFromRange();\n\t\t}\n\t}\n\n\t/**\n\t * Pick the renderer module based on RenderMode option.\n\t *\n\t * @returns {object} The renderer module { render, wireEvents }\n\t */\n\t_resolveRenderer()\n\t{\n\t\tswitch (this.options.RenderMode)\n\t\t{\n\t\t\tcase 'consoleui':\n\t\t\t\treturn libRendererConsoleUI;\n\t\t\tcase 'cli':\n\t\t\t\treturn libRendererCLI;\n\t\t\tcase 'browser':\n\t\t\tdefault:\n\t\t\t\treturn libRendererBrowser;\n\t\t}\n\t}\n\n\t// --- Data Access ---\n\n\t/**\n\t * Get the current bin data array.\n\t *\n\t * Reads from the configured DataAddress in AppData, falling back to\n\t * the static Bins option.\n\t *\n\t * @returns {Array} Array of bin objects\n\t */\n\tgetBins()\n\t{\n\t\tif (this.options.DataAddress)\n\t\t{\n\t\t\tconst tmpAddressSpace =\n\t\t\t{\n\t\t\t\tFable: this.fable,\n\t\t\t\tPict: this.fable,\n\t\t\t\tAppData: this.AppData,\n\t\t\t\tBundle: this.Bundle,\n\t\t\t\tOptions: this.options\n\t\t\t};\n\t\t\tlet tmpData = this.fable.manifest.getValueByHash(tmpAddressSpace, this.options.DataAddress);\n\t\t\tif (Array.isArray(tmpData))\n\t\t\t{\n\t\t\t\treturn tmpData;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis.log.warn(`PICT-Histogram DataAddress [${this.options.DataAddress}] did not return an array.`);\n\t\t\t}\n\t\t}\n\n\t\treturn this.options.Bins || [];\n\t}\n\n\t/**\n\t * Set the bins programmatically (updates the Bins option).\n\t *\n\t * @param {Array} pBins - Array of bin objects { Label, Value, ... }\n\t */\n\tsetBins(pBins)\n\t{\n\t\tif (!Array.isArray(pBins))\n\t\t{\n\t\t\tthis.log.warn('PICT-Histogram setBins requires an array.');\n\t\t\treturn;\n\t\t}\n\t\tthis.options.Bins = pBins;\n\n\t\t// If we also have a DataAddress, write through\n\t\tif (this.options.DataAddress)\n\t\t{\n\t\t\tconst tmpAddressSpace =\n\t\t\t{\n\t\t\t\tFable: this.fable,\n\t\t\t\tPict: this.fable,\n\t\t\t\tAppData: this.AppData,\n\t\t\t\tBundle: this.Bundle,\n\t\t\t\tOptions: this.options\n\t\t\t};\n\t\t\tthis.fable.manifest.setValueByHash(tmpAddressSpace, this.options.DataAddress, pBins);\n\t\t}\n\t}\n\n\t// --- Selection Logic ---\n\n\t/**\n\t * Check whether a bin index is currently selected.\n\t *\n\t * @param {number} pIndex\n\t * @returns {boolean}\n\t */\n\tisIndexSelected(pIndex)\n\t{\n\t\tif (!this.options.Selectable)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\treturn (pIndex === this._selectionRangeStart || pIndex === this._selectionRangeEnd);\n\t\t}\n\n\t\treturn this._selectedIndices.has(pIndex);\n\t}\n\n\t/**\n\t * Check whether a bin index falls within the current range selection\n\t * (but is not one of the range endpoints).\n\t *\n\t * @param {number} pIndex\n\t * @returns {boolean}\n\t */\n\tisIndexInRange(pIndex)\n\t{\n\t\tif (!this.options.Selectable || this.options.SelectionMode !== 'range')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn (pIndex > this._selectionRangeStart && pIndex < this._selectionRangeEnd);\n\t}\n\n\t/**\n\t * Get the current selection state.\n\t *\n\t * @returns {object} Selection descriptor\n\t */\n\tgetSelection()\n\t{\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\tlet tmpBins = this.getBins();\n\t\t\tlet tmpIndices = [];\n\t\t\tfor (let i = this._selectionRangeStart; i <= this._selectionRangeEnd; i++)\n\t\t\t{\n\t\t\t\ttmpIndices.push(i);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tMode: 'range',\n\t\t\t\tRangeStart: this._selectionRangeStart,\n\t\t\t\tRangeEnd: this._selectionRangeEnd,\n\t\t\t\tSelectedIndices: tmpIndices,\n\t\t\t\tStartLabel: (tmpBins[this._selectionRangeStart] || {})[this.options.LabelProperty],\n\t\t\t\tEndLabel: (tmpBins[this._selectionRangeEnd] || {})[this.options.LabelProperty]\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn {\n\t\t\t\tMode: this.options.SelectionMode,\n\t\t\t\tSelectedIndices: Array.from(this._selectedIndices).sort((a, b) => a - b)\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Programmatically set the selection.\n\t *\n\t * @param {object|Array} pSelection - For range: { Start, End }; for single/multiple: array of indices\n\t */\n\tsetSelection(pSelection)\n\t{\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\tif (pSelection && typeof (pSelection.Start) === 'number' && typeof (pSelection.End) === 'number')\n\t\t\t{\n\t\t\t\tthis._selectionRangeStart = pSelection.Start;\n\t\t\t\tthis._selectionRangeEnd = pSelection.End;\n\t\t\t\tthis._syncSelectionFromRange();\n\t\t\t}\n\t\t}\n\t\telse if (Array.isArray(pSelection))\n\t\t{\n\t\t\tthis._selectedIndices = new Set(pSelection);\n\t\t}\n\n\t\tthis._writeSelectionToAddress();\n\t}\n\n\t/**\n\t * Handle a bar click in single or multiple selection mode.\n\t *\n\t * @param {number} pIndex - The clicked bin index\n\t */\n\thandleBarClick(pIndex)\n\t{\n\t\tif (this.options.SelectionMode === 'single')\n\t\t{\n\t\t\tthis._selectedIndices.clear();\n\t\t\tthis._selectedIndices.add(pIndex);\n\t\t}\n\t\telse if (this.options.SelectionMode === 'multiple')\n\t\t{\n\t\t\tif (this._selectedIndices.has(pIndex))\n\t\t\t{\n\t\t\t\tthis._selectedIndices.delete(pIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis._selectedIndices.add(pIndex);\n\t\t\t}\n\t\t}\n\n\t\tthis._writeSelectionToAddress();\n\t\tthis.onSelectionChange(this.getSelection());\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Handle a bar click in range mode — moves the nearest handle.\n\t *\n\t * @param {number} pIndex - The clicked bin index\n\t */\n\thandleRangeBarClick(pIndex)\n\t{\n\t\tlet tmpDistStart = Math.abs(pIndex - this._selectionRangeStart);\n\t\tlet tmpDistEnd = Math.abs(pIndex - this._selectionRangeEnd);\n\n\t\tif (tmpDistStart <= tmpDistEnd)\n\t\t{\n\t\t\tthis._selectionRangeStart = Math.min(pIndex, this._selectionRangeEnd);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis._selectionRangeEnd = Math.max(pIndex, this._selectionRangeStart);\n\t\t}\n\n\t\tthis._syncSelectionFromRange();\n\t\tthis._writeSelectionToAddress();\n\t\tthis.onSelectionChange(this.getSelection());\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Sync _selectedIndices from the range bounds (so getSelection is consistent).\n\t */\n\t_syncSelectionFromRange()\n\t{\n\t\tthis._selectedIndices.clear();\n\t\tfor (let i = this._selectionRangeStart; i <= this._selectionRangeEnd; i++)\n\t\t{\n\t\t\tthis._selectedIndices.add(i);\n\t\t}\n\t}\n\n\t/**\n\t * Write the current selection state to the configured SelectionDataAddress.\n\t */\n\t_writeSelectionToAddress()\n\t{\n\t\tif (!this.options.SelectionDataAddress)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tconst tmpAddressSpace =\n\t\t{\n\t\t\tFable: this.fable,\n\t\t\tPict: this.fable,\n\t\t\tAppData: this.AppData,\n\t\t\tBundle: this.Bundle,\n\t\t\tOptions: this.options\n\t\t};\n\n\t\tthis.fable.manifest.setValueByHash(tmpAddressSpace, this.options.SelectionDataAddress, this.getSelection());\n\t}\n\n\t/**\n\t * Hook for subclasses or consumers to react to selection changes.\n\t *\n\t * @param {object} pSelection - The new selection state\n\t */\n\tonSelectionChange(pSelection)\n\t{\n\t\t// Override in subclass or assign externally\n\t}\n\n\t// --- Lifecycle Hooks ---\n\n\tonBeforeInitialize()\n\t{\n\t\tsuper.onBeforeInitialize();\n\t\treturn super.onBeforeInitialize();\n\t}\n\n\tonAfterRender(pRenderable)\n\t{\n\t\t// Inject CSS\n\t\tthis.pict.CSSMap.injectCSS();\n\n\t\tif (!this.initialRenderComplete)\n\t\t{\n\t\t\tthis.onAfterInitialRender();\n\t\t\tthis.initialRenderComplete = true;\n\t\t}\n\n\t\treturn super.onAfterRender(pRenderable);\n\t}\n\n\tonAfterInitialRender()\n\t{\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Render the histogram using the active renderer and wire events.\n\t */\n\trenderHistogram()\n\t{\n\t\t// Ensure CSS is injected (covers both lifecycle and direct calls)\n\t\tif (this.pict.CSSMap)\n\t\t{\n\t\t\tthis.pict.CSSMap.injectCSS();\n\t\t}\n\t\tthis._renderer.render(this);\n\t\tthis._renderer.wireEvents(this);\n\t\tthis.initialRenderComplete = true;\n\t}\n\n\t// --- Data Marshaling ---\n\n\tmarshalToView()\n\t{\n\t\tsuper.marshalToView();\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\tmarshalFromView()\n\t{\n\t\tsuper.marshalFromView();\n\t\tthis._writeSelectionToAddress();\n\t}\n\n\t// --- Public API ---\n\n\t/**\n\t * Change the orientation and re-render.\n\t *\n\t * @param {string} pOrientation - \"vertical\" or \"horizontal\"\n\t */\n\tsetOrientation(pOrientation)\n\t{\n\t\tif (pOrientation !== 'vertical' && pOrientation !== 'horizontal')\n\t\t{\n\t\t\tthis.log.warn(`PICT-Histogram invalid orientation: ${pOrientation}`);\n\t\t\treturn;\n\t\t}\n\t\tthis.options.Orientation = pOrientation;\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\t/**\n\t * Change the render mode and re-render.\n\t *\n\t * @param {string} pRenderMode - \"browser\", \"consoleui\", or \"cli\"\n\t */\n\tsetRenderMode(pRenderMode)\n\t{\n\t\tthis.options.RenderMode = pRenderMode;\n\t\tthis._renderer = this._resolveRenderer();\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\t/**\n\t * Convenience: get the text representation (useful for CLI/consoleui).\n\t *\n\t * @returns {string}\n\t */\n\ttoText()\n\t{\n\t\tif (this.options.Orientation === 'vertical')\n\t\t{\n\t\t\treturn libRendererConsoleUI.renderVertical(this);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn libRendererConsoleUI.renderHorizontal(this);\n\t\t}\n\t}\n}\n\nmodule.exports = PictSectionHistogram;\n\nmodule.exports.default_configuration = _DefaultConfiguration;\nmodule.exports.renderers = {\n\tbrowser: libRendererBrowser,\n\tconsoleui: libRendererConsoleUI,\n\tcli: libRendererCLI\n};\n\n},{\"./Pict-Section-Histogram-DefaultConfiguration.js\":7,\"./renderers/Pict-Histogram-Renderer-Browser.js\":9,\"./renderers/Pict-Histogram-Renderer-CLI.js\":10,\"./renderers/Pict-Histogram-Renderer-ConsoleUI.js\":11,\"pict-view\":13}],9:[function(require,module,exports){\n/**\n * Browser renderer for pict-section-histogram.\n *\n * Renders the histogram as HTML/CSS elements using the Pict ContentAssignment\n * pipeline. Also wires up interactive selection (click, drag-slider) via\n * DOM event listeners.\n *\n * @module Pict-Histogram-Renderer-Browser\n */\n\n/**\n * Build the HTML string for a single bar group (bar + optional labels).\n *\n * @param {object} pBin - The bin data { Label, Value, ... }\n * @param {number} pIndex - Index of the bin\n * @param {number} pBarSize - Computed bar size in pixels\n * @param {object} pOptions - View options\n * @param {boolean} pIsSelected - Whether this bin is selected\n * @param {boolean} pInRange - Whether this bin is inside the range selection\n * @param {number} pLabelWidth - Fixed label width in pixels (horizontal mode)\n * @returns {string} HTML fragment\n */\nfunction buildBarGroupHTML(pBin, pIndex, pBarSize, pOptions, pIsSelected, pInRange, pLabelWidth)\n{\n\tlet tmpLabel = pBin[pOptions.LabelProperty] || '';\n\tlet tmpValue = pBin[pOptions.ValueProperty] || 0;\n\tlet tmpVertical = (pOptions.Orientation === 'vertical');\n\tlet tmpBarColor = pIsSelected ? pOptions.SelectedBarColor\n\t\t: pInRange ? pOptions.SelectionRangeColor\n\t\t: pOptions.BarColor;\n\n\tlet tmpSelectableClass = pOptions.Selectable ? ' pict-histogram-selectable' : '';\n\tlet tmpSelectedClass = pIsSelected ? ' pict-histogram-selected' : '';\n\tlet tmpInRangeClass = pInRange ? ' pict-histogram-in-range' : '';\n\n\tlet tmpFillMode = pOptions.FillContainer;\n\n\tlet tmpBarStyle = '';\n\tif (tmpVertical)\n\t{\n\t\tif (tmpFillMode)\n\t\t{\n\t\t\ttmpBarStyle = `height:${pBarSize}px;background-color:${tmpBarColor};`;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpBarStyle = `height:${pBarSize}px;width:${pOptions.BarThickness}px;background-color:${tmpBarColor};`;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (tmpFillMode)\n\t\t{\n\t\t\ttmpBarStyle = `width:${pBarSize}px;background-color:${tmpBarColor};`;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpBarStyle = `width:${pBarSize}px;height:${pOptions.BarThickness}px;background-color:${tmpBarColor};`;\n\t\t}\n\t}\n\n\tlet tmpGroupWidth = pOptions.BarThickness + pOptions.BarGap;\n\tlet tmpGroupStyle = '';\n\tif (tmpFillMode)\n\t{\n\t\t// No fixed dimensions — CSS flex:1 handles sizing\n\t\ttmpGroupStyle = '';\n\t}\n\telse if (tmpVertical)\n\t{\n\t\ttmpGroupStyle = `margin:0 ${pOptions.BarGap / 2}px;width:${tmpGroupWidth}px;`;\n\t}\n\telse\n\t{\n\t\ttmpGroupStyle = `margin:${pOptions.BarGap / 2}px 0;`;\n\t}\n\n\tlet tmpHTML = `<div class=\"pict-histogram-bar-group\" style=\"${tmpGroupStyle}\" data-histogram-index=\"${pIndex}\">`;\n\n\tif (tmpVertical)\n\t{\n\t\t// Value label above bar (skipped in fill mode — values don't fit in narrow columns)\n\t\tif (pOptions.ShowValues && !tmpFillMode)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-value-label\" style=\"width:${tmpGroupWidth}px;\">${tmpValue}</div>`;\n\t\t}\n\t\t// Bar\n\t\ttmpHTML += `<div class=\"pict-histogram-bar${tmpSelectableClass}${tmpSelectedClass}${tmpInRangeClass}\" style=\"${tmpBarStyle}\" data-histogram-index=\"${pIndex}\"></div>`;\n\t\t// Bin label below bar (skipped in fill mode — labels rendered in a separate row)\n\t\tif (pOptions.ShowLabels && !tmpFillMode)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-bin-label\" style=\"width:${tmpGroupWidth}px;\">${tmpLabel}</div>`;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Bin label to the left (fixed width so bars align)\n\t\tif (pOptions.ShowLabels)\n\t\t{\n\t\t\tlet tmpLabelStyle = pLabelWidth ? `width:${pLabelWidth}px;min-width:${pLabelWidth}px;` : '';\n\t\t\ttmpHTML += `<div class=\"pict-histogram-bin-label\" style=\"${tmpLabelStyle}\">${tmpLabel}</div>`;\n\t\t}\n\t\t// Bar\n\t\ttmpHTML += `<div class=\"pict-histogram-bar${tmpSelectableClass}${tmpSelectedClass}${tmpInRangeClass}\" style=\"${tmpBarStyle}\" data-histogram-index=\"${pIndex}\"></div>`;\n\t\t// Value label to the right\n\t\tif (pOptions.ShowValues)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-value-label\">${tmpValue}</div>`;\n\t\t}\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Build the HTML for the range-slider overlay (used in \"range\" selection mode).\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} HTML fragment\n */\nfunction buildRangeSliderHTML(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '';\n\t}\n\n\tlet tmpRangeStart = pView._selectionRangeStart;\n\tlet tmpRangeEnd = pView._selectionRangeEnd;\n\tlet tmpMax = tmpBins.length - 1;\n\n\t// Calculate percentage positions for the handles\n\tlet tmpStartPct = (tmpMax > 0) ? ((tmpRangeStart / tmpMax) * 100) : 0;\n\tlet tmpEndPct = (tmpMax > 0) ? ((tmpRangeEnd / tmpMax) * 100) : 100;\n\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\n\tlet tmpHTML = '<div class=\"pict-histogram-range-slider-container\">';\n\ttmpHTML += '<div class=\"pict-histogram-range-track\"></div>';\n\n\tif (tmpVertical)\n\t{\n\t\ttmpHTML += `<div class=\"pict-histogram-range-fill\" style=\"left:${tmpStartPct}%;right:${100 - tmpEndPct}%;\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-start\" tabindex=\"0\" style=\"left:${tmpStartPct}%;\" data-handle=\"start\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-end\" tabindex=\"0\" style=\"left:${tmpEndPct}%;\" data-handle=\"end\"></div>`;\n\t}\n\telse\n\t{\n\t\ttmpHTML += `<div class=\"pict-histogram-range-fill\" style=\"top:${tmpStartPct}%;bottom:${100 - tmpEndPct}%;\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-start\" tabindex=\"0\" style=\"top:${tmpStartPct}%;\" data-handle=\"start\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-end\" tabindex=\"0\" style=\"top:${tmpEndPct}%;\" data-handle=\"end\"></div>`;\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Build the label row for FillContainer vertical mode.\n *\n * Labels are rendered in a separate flex row below the axis line, with\n * automatic interval calculation to avoid overlap when there are many bins.\n *\n * @param {object} pView - The histogram view instance\n * @param {Array} pBins - The bin data array\n * @returns {string} HTML fragment\n */\nfunction buildFillLabelRow(pView, pBins)\n{\n\tif (!pBins || pBins.length === 0)\n\t{\n\t\treturn '';\n\t}\n\n\t// Determine label interval: explicit setting or auto-compute\n\tlet tmpLabelInterval = pView.options.LabelInterval || 0;\n\tif (tmpLabelInterval <= 0)\n\t{\n\t\t// Auto-compute: space labels approximately 80px apart\n\t\tlet tmpTargetElementSet = pView.services.ContentAssignment.getElement(pView.options.TargetElementAddress);\n\t\tlet tmpContainerWidth = 800;\n\t\tif (tmpTargetElementSet && tmpTargetElementSet.length > 0 && tmpTargetElementSet[0])\n\t\t{\n\t\t\ttmpContainerWidth = tmpTargetElementSet[0].clientWidth || 800;\n\t\t}\n\t\tif (pBins.length > 0)\n\t\t{\n\t\t\tlet tmpBarWidth = tmpContainerWidth / pBins.length;\n\t\t\ttmpLabelInterval = Math.max(1, Math.ceil(80 / tmpBarWidth));\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLabelInterval = 1;\n\t\t}\n\t}\n\n\tlet tmpHTML = '<div class=\"pict-histogram-label-row\">';\n\n\tfor (let i = 0; i < pBins.length; i++)\n\t{\n\t\tlet tmpIsLabeled = (i % tmpLabelInterval === 0);\n\t\tif (tmpIsLabeled)\n\t\t{\n\t\t\tlet tmpLabel = pBins[i][pView.options.LabelProperty] || '';\n\t\t\t// Span covers this label and the unlabeled bars until the next label\n\t\t\tlet tmpSpan = Math.min(tmpLabelInterval, pBins.length - i);\n\t\t\ttmpHTML += `<div class=\"pict-histogram-fill-label\" style=\"flex:${tmpSpan};\">${tmpLabel}</div>`;\n\t\t\ti += tmpSpan - 1;\n\t\t}\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Render the full histogram into the target element.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\tpView.services.ContentAssignment.assignContent(\n\t\t\tpView.options.TargetElementAddress,\n\t\t\t'<div class=\"pict-histogram-container\"><em>No histogram data</em></div>'\n\t\t);\n\t\treturn;\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][pView.options.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\tlet tmpOrientationClass = tmpVertical ? 'pict-histogram-vertical' : 'pict-histogram-horizontal';\n\tlet tmpFillClass = pView.options.FillContainer ? ' pict-histogram-fill' : '';\n\n\t// For horizontal mode (non-fill), measure the longest label so all labels share the same width\n\tlet tmpLabelWidth = 0;\n\tif (!tmpVertical && pView.options.ShowLabels && !pView.options.FillContainer)\n\t{\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][pView.options.LabelProperty] || '');\n\t\t\t// Approximate character width at 11px font: ~6.5px per character\n\t\t\tlet tmpEstWidth = tmpLabel.length * 6.5 + 8;\n\t\t\tif (tmpEstWidth > tmpLabelWidth)\n\t\t\t{\n\t\t\t\ttmpLabelWidth = tmpEstWidth;\n\t\t\t}\n\t\t}\n\t\ttmpLabelWidth = Math.max(tmpLabelWidth, 40);\n\t}\n\n\tlet tmpHTML = `<div class=\"pict-histogram-container ${tmpOrientationClass}${tmpFillClass}\">`;\n\ttmpHTML += `<div class=\"pict-histogram-chart ${tmpOrientationClass}${tmpFillClass}\">`;\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][pView.options.ValueProperty] || 0;\n\t\tlet tmpBarSize = Math.round((tmpVal / tmpMaxValue) * pView.options.MaxBarSize);\n\t\tif (tmpVal > 0 && tmpBarSize < 1)\n\t\t{\n\t\t\ttmpBarSize = 1;\n\t\t}\n\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\n\t\ttmpHTML += buildBarGroupHTML(tmpBins[i], i, tmpBarSize, pView.options, tmpIsSelected, tmpInRange, tmpLabelWidth);\n\t}\n\n\ttmpHTML += '</div>';\n\n\t// In FillContainer vertical mode, render axis line and label row separately\n\tif (pView.options.FillContainer && tmpVertical && pView.options.ShowLabels)\n\t{\n\t\ttmpHTML += '<div class=\"pict-histogram-axis-line\"></div>';\n\t\ttmpHTML += buildFillLabelRow(pView, tmpBins);\n\t}\n\n\t// Range slider for \"range\" selection mode\n\tif (pView.options.Selectable && pView.options.SelectionMode === 'range')\n\t{\n\t\ttmpHTML += buildRangeSliderHTML(pView);\n\t}\n\n\ttmpHTML += '</div>';\n\n\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpHTML);\n}\n\n/**\n * Wire up DOM event listeners for interactivity (click selection, range drag).\n *\n * @param {object} pView - The histogram view instance\n */\nfunction wireEvents(pView)\n{\n\tif (!pView.options.Selectable)\n\t{\n\t\treturn;\n\t}\n\n\tlet tmpTargetElementSet = pView.services.ContentAssignment.getElement(pView.options.TargetElementAddress);\n\tif (!tmpTargetElementSet || tmpTargetElementSet.length < 1)\n\t{\n\t\treturn;\n\t}\n\tlet tmpContainer = tmpTargetElementSet[0];\n\tif (!tmpContainer)\n\t{\n\t\treturn;\n\t}\n\n\t// --- Bar click selection (single / multiple modes) ---\n\tif (pView.options.SelectionMode === 'single' || pView.options.SelectionMode === 'multiple')\n\t{\n\t\tlet tmpBars = tmpContainer.querySelectorAll('.pict-histogram-bar[data-histogram-index]');\n\t\tfor (let i = 0; i < tmpBars.length; i++)\n\t\t{\n\t\t\ttmpBars[i].addEventListener('click', (pEvent) =>\n\t\t\t{\n\t\t\t\tlet tmpIndex = parseInt(pEvent.currentTarget.getAttribute('data-histogram-index'), 10);\n\t\t\t\tif (isNaN(tmpIndex))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpView.handleBarClick(tmpIndex);\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Range slider drag ---\n\tif (pView.options.SelectionMode === 'range')\n\t{\n\t\t// Also allow clicking bars to move nearest handle\n\t\tlet tmpBars = tmpContainer.querySelectorAll('.pict-histogram-bar[data-histogram-index]');\n\t\tfor (let i = 0; i < tmpBars.length; i++)\n\t\t{\n\t\t\ttmpBars[i].addEventListener('click', (pEvent) =>\n\t\t\t{\n\t\t\t\tlet tmpIndex = parseInt(pEvent.currentTarget.getAttribute('data-histogram-index'), 10);\n\t\t\t\tif (isNaN(tmpIndex))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpView.handleRangeBarClick(tmpIndex);\n\t\t\t});\n\t\t}\n\n\t\tlet tmpHandles = tmpContainer.querySelectorAll('.pict-histogram-range-handle');\n\t\tfor (let i = 0; i < tmpHandles.length; i++)\n\t\t{\n\t\t\twireRangeHandle(pView, tmpHandles[i], tmpContainer);\n\t\t}\n\t}\n}\n\n/**\n * Wire drag behavior on a single range handle element.\n *\n * @param {object} pView - The histogram view instance\n * @param {Element} pHandle - The handle DOM element\n * @param {Element} pContainer - The histogram container element\n */\nfunction wireRangeHandle(pView, pHandle, pContainer)\n{\n\tlet tmpHandleType = pHandle.getAttribute('data-handle'); // \"start\" or \"end\"\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\n\tlet tmpDragging = false;\n\n\tfunction getSliderBounds()\n\t{\n\t\t// Re-query from pContainer every time because renderHistogram() replaces\n\t\t// the inner HTML, detaching any previously-captured slider element.\n\t\tlet tmpSlider = pContainer.querySelector('.pict-histogram-range-slider-container');\n\t\tif (!tmpSlider)\n\t\t{\n\t\t\treturn { start: 0, size: 1 };\n\t\t}\n\t\tlet tmpRect = tmpSlider.getBoundingClientRect();\n\t\tif (tmpVertical)\n\t\t{\n\t\t\treturn { start: tmpRect.left, size: tmpRect.width || 1 };\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn { start: tmpRect.top, size: tmpRect.height || 1 };\n\t\t}\n\t}\n\n\tfunction onPointerMove(pEvent)\n\t{\n\t\tif (!tmpDragging)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBins = pView.getBins();\n\t\tif (!tmpBins || tmpBins.length === 0)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBounds = getSliderBounds();\n\t\tlet tmpPos = tmpVertical ? pEvent.clientX : pEvent.clientY;\n\t\tlet tmpPct = (tmpPos - tmpBounds.start) / tmpBounds.size;\n\t\ttmpPct = Math.max(0, Math.min(1, tmpPct));\n\n\t\tlet tmpIndex = Math.round(tmpPct * (tmpBins.length - 1));\n\n\t\tif (tmpHandleType === 'start')\n\t\t{\n\t\t\tif (tmpIndex > pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpIndex = pView._selectionRangeEnd;\n\t\t\t}\n\t\t\tpView._selectionRangeStart = tmpIndex;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (tmpIndex < pView._selectionRangeStart)\n\t\t\t{\n\t\t\t\ttmpIndex = pView._selectionRangeStart;\n\t\t\t}\n\t\t\tpView._selectionRangeEnd = tmpIndex;\n\t\t}\n\n\t\tpView._syncSelectionFromRange();\n\t\tpView.renderHistogram();\n\t}\n\n\tfunction onPointerUp()\n\t{\n\t\tif (!tmpDragging)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\ttmpDragging = false;\n\t\tif (typeof (document) !== 'undefined')\n\t\t{\n\t\t\tdocument.removeEventListener('mousemove', onPointerMove);\n\t\t\tdocument.removeEventListener('mouseup', onPointerUp);\n\t\t}\n\t}\n\n\tpHandle.addEventListener('mousedown', (pEvent) =>\n\t{\n\t\tpEvent.preventDefault();\n\t\ttmpDragging = true;\n\t\tif (typeof (document) !== 'undefined')\n\t\t{\n\t\t\tdocument.addEventListener('mousemove', onPointerMove);\n\t\t\tdocument.addEventListener('mouseup', onPointerUp);\n\t\t}\n\t});\n}\n\nmodule.exports = { render, wireEvents };\n\n},{}],10:[function(require,module,exports){\n(function (process){(function (){\n/**\n * CLI renderer for pict-section-histogram.\n *\n * Renders the histogram as ANSI-colored text written directly to stdout\n * (or through the Pict ContentAssignment pipeline if available).\n *\n * This mode is intended for command-line tools that print histogram output\n * without a full terminal UI framework.\n *\n * @module Pict-Histogram-Renderer-CLI\n */\n\n// ANSI color codes (basic 16-color)\nconst ANSI_COLORS = {\n\t'black': '\\x1b[30m',\n\t'red': '\\x1b[31m',\n\t'green': '\\x1b[32m',\n\t'yellow': '\\x1b[33m',\n\t'blue': '\\x1b[34m',\n\t'magenta': '\\x1b[35m',\n\t'cyan': '\\x1b[36m',\n\t'white': '\\x1b[37m',\n\t'reset': '\\x1b[0m',\n\t'bold': '\\x1b[1m',\n\t'dim': '\\x1b[2m'\n};\n\n/**\n * Map a CSS-ish color string to the nearest ANSI color.\n *\n * @param {string} pColor - A color string (name or hex)\n * @returns {string} ANSI escape code\n */\nfunction colorToAnsi(pColor)\n{\n\tif (!pColor)\n\t{\n\t\treturn ANSI_COLORS.blue;\n\t}\n\n\tlet tmpLower = pColor.toLowerCase();\n\n\t// Direct name match\n\tif (ANSI_COLORS[tmpLower])\n\t{\n\t\treturn ANSI_COLORS[tmpLower];\n\t}\n\n\t// Simple hex-to-nearest mapping\n\tif (tmpLower.charAt(0) === '#' && tmpLower.length >= 7)\n\t{\n\t\tlet tmpR = parseInt(tmpLower.substring(1, 3), 16);\n\t\tlet tmpG = parseInt(tmpLower.substring(3, 5), 16);\n\t\tlet tmpB = parseInt(tmpLower.substring(5, 7), 16);\n\n\t\t// Pick nearest basic color\n\t\tif (tmpG > tmpR && tmpG > tmpB)\n\t\t{\n\t\t\treturn ANSI_COLORS.green;\n\t\t}\n\t\tif (tmpR > tmpG && tmpR > tmpB)\n\t\t{\n\t\t\treturn ANSI_COLORS.red;\n\t\t}\n\t\tif (tmpB > tmpR && tmpB > tmpG)\n\t\t{\n\t\t\treturn ANSI_COLORS.blue;\n\t\t}\n\t\tif (tmpR > 200 && tmpG > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.yellow;\n\t\t}\n\t\tif (tmpR > 200 && tmpB > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.magenta;\n\t\t}\n\t\tif (tmpG > 200 && tmpB > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.cyan;\n\t\t}\n\t}\n\n\treturn ANSI_COLORS.blue;\n}\n\n/**\n * Render a vertical CLI histogram.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The ANSI text output\n */\nfunction renderVertical(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpHeight = tmpOptions.TextHeight || 15;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\tlet tmpBarColor = colorToAnsi(tmpOptions.BarColor);\n\tlet tmpSelectedColor = colorToAnsi(tmpOptions.SelectedBarColor);\n\tlet tmpRangeColor = colorToAnsi(tmpOptions.SelectionRangeColor);\n\tlet tmpReset = ANSI_COLORS.reset;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)\\n';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpValueAxisWidth = String(tmpMaxValue).length + 1;\n\tlet tmpLines = [];\n\n\tfor (let tmpRow = tmpHeight; tmpRow >= 1; tmpRow--)\n\t{\n\t\tlet tmpLine = '';\n\n\t\t// Axis labels\n\t\tif (tmpRow === tmpHeight)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft(String(tmpMaxValue), tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse if (tmpRow === 1)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft('0', tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse if (tmpRow === Math.ceil(tmpHeight / 2))\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft(String(Math.round(tmpMaxValue / 2)), tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft('', tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\t\tlet tmpBarHeight = (tmpVal / tmpMaxValue) * tmpHeight;\n\t\t\tlet tmpFullRows = Math.floor(tmpBarHeight);\n\t\t\tlet tmpFraction = tmpBarHeight - tmpFullRows;\n\n\t\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\t\tlet tmpColor = tmpIsSelected ? tmpSelectedColor : (tmpInRange ? tmpRangeColor : tmpBarColor);\n\n\t\t\tlet tmpChar = ' ';\n\t\t\tif (tmpRow <= tmpFullRows)\n\t\t\t{\n\t\t\t\ttmpChar = tmpBarChar;\n\t\t\t}\n\t\t\telse if (tmpRow === tmpFullRows + 1 && tmpFraction > 0)\n\t\t\t{\n\t\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\t\ttmpChar = tmpPartials[tmpPartialIndex];\n\t\t\t}\n\n\t\t\tif (tmpChar !== ' ')\n\t\t\t{\n\t\t\t\ttmpLine += ' ' + tmpColor + tmpChar + tmpChar + tmpChar + tmpReset;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpLine += ' ';\n\t\t\t}\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Bottom axis\n\tlet tmpAxisLine = ANSI_COLORS.dim + padLeft('', tmpValueAxisWidth) + '+';\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\ttmpAxisLine += '----';\n\t}\n\ttmpAxisLine += tmpReset;\n\ttmpLines.push(tmpAxisLine);\n\n\t// Labels\n\tif (tmpOptions.ShowLabels)\n\t{\n\t\tlet tmpLabelLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\t\ttmpLabelLine += padCenter(tmpLabel.substring(0, 4), 4);\n\t\t}\n\t\ttmpLines.push(tmpLabelLine);\n\t}\n\n\t// Range selection info\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpStart = pView._selectionRangeStart;\n\t\tlet tmpEnd = pView._selectionRangeEnd;\n\t\tlet tmpStartLabel = tmpBins[tmpStart] ? tmpBins[tmpStart][tmpOptions.LabelProperty] : tmpStart;\n\t\tlet tmpEndLabel = tmpBins[tmpEnd] ? tmpBins[tmpEnd][tmpOptions.LabelProperty] : tmpEnd;\n\t\ttmpLines.push('');\n\t\ttmpLines.push(ANSI_COLORS.bold + ' Selection: ' + tmpStartLabel + ' - ' + tmpEndLabel + tmpReset);\n\t}\n\n\treturn tmpLines.join('\\n') + '\\n';\n}\n\n/**\n * Render a horizontal CLI histogram.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The ANSI text output\n */\nfunction renderHorizontal(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpWidth = tmpOptions.TextWidth || 60;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpBarColor = colorToAnsi(tmpOptions.BarColor);\n\tlet tmpSelectedColor = colorToAnsi(tmpOptions.SelectedBarColor);\n\tlet tmpRangeColor = colorToAnsi(tmpOptions.SelectionRangeColor);\n\tlet tmpReset = ANSI_COLORS.reset;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)\\n';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tlet tmpMaxLabelLen = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tif (tmpLabel.length > tmpMaxLabelLen)\n\t\t{\n\t\t\ttmpMaxLabelLen = tmpLabel.length;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpLabelWidth = Math.min(tmpMaxLabelLen, 12);\n\tlet tmpValueWidth = String(tmpMaxValue).length;\n\tlet tmpBarWidth = tmpWidth - tmpLabelWidth - tmpValueWidth - 4;\n\tif (tmpBarWidth < 10)\n\t{\n\t\ttmpBarWidth = 10;\n\t}\n\n\tlet tmpLines = [];\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tlet tmpBarLen = Math.round((tmpVal / tmpMaxValue) * tmpBarWidth);\n\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\tlet tmpColor = tmpIsSelected ? tmpSelectedColor : (tmpInRange ? tmpRangeColor : tmpBarColor);\n\n\t\tlet tmpBar = '';\n\t\tfor (let j = 0; j < tmpBarLen; j++)\n\t\t{\n\t\t\ttmpBar += tmpBarChar;\n\t\t}\n\n\t\tlet tmpLine = ANSI_COLORS.dim + padRight(tmpLabel.substring(0, tmpLabelWidth), tmpLabelWidth) + ' |' + tmpReset;\n\t\ttmpLine += tmpColor + tmpBar + tmpReset;\n\t\ttmpLine += ' ' + tmpVal;\n\n\t\tif (tmpIsSelected)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.bold + ' *' + tmpReset;\n\t\t}\n\t\telse if (tmpInRange)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + ' ~' + tmpReset;\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Range info\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpStart = pView._selectionRangeStart;\n\t\tlet tmpEnd = pView._selectionRangeEnd;\n\t\tlet tmpStartLabel = tmpBins[tmpStart] ? tmpBins[tmpStart][tmpOptions.LabelProperty] : tmpStart;\n\t\tlet tmpEndLabel = tmpBins[tmpEnd] ? tmpBins[tmpEnd][tmpOptions.LabelProperty] : tmpEnd;\n\t\ttmpLines.push('');\n\t\ttmpLines.push(ANSI_COLORS.bold + ' Selection: ' + tmpStartLabel + ' - ' + tmpEndLabel + tmpReset);\n\t}\n\n\treturn tmpLines.join('\\n') + '\\n';\n}\n\n/**\n * Render in CLI mode. Writes to ContentAssignment if available, otherwise\n * falls back to process.stdout.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpText;\n\tif (pView.options.Orientation === 'vertical')\n\t{\n\t\ttmpText = renderVertical(pView);\n\t}\n\telse\n\t{\n\t\ttmpText = renderHorizontal(pView);\n\t}\n\n\t// Try ContentAssignment first (might be mocked in tests or bridged)\n\tif (pView.services && pView.services.ContentAssignment)\n\t{\n\t\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpText);\n\t}\n\telse if (typeof (process) !== 'undefined' && process.stdout)\n\t{\n\t\tprocess.stdout.write(tmpText);\n\t}\n}\n\n// No interactive events in CLI mode\nfunction wireEvents()\n{\n\t// No-op for CLI\n}\n\n// --- Utility ---\n\nfunction padLeft(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = ' ' + tmpStr;\n\t}\n\treturn tmpStr;\n}\n\nfunction padRight(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = tmpStr + ' ';\n\t}\n\treturn tmpStr;\n}\n\nfunction padCenter(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = (tmpStr.length % 2 === 0) ? (tmpStr + ' ') : (' ' + tmpStr);\n\t}\n\treturn tmpStr;\n}\n\nmodule.exports = { render, wireEvents, renderVertical, renderHorizontal, colorToAnsi, ANSI_COLORS };\n\n}).call(this)}).call(this,require('_process'))\n\n},{\"_process\":14}],11:[function(require,module,exports){\n/**\n * Console UI (blessed) renderer for pict-section-histogram.\n *\n * Renders the histogram as text art through the Pict ContentAssignment\n * pipeline, suitable for blessed/ncurses terminal UI widgets.\n *\n * The output is assigned via ContentAssignment so the pict-terminalui\n * bridge (customAssignFunction) can project it into blessed boxes.\n *\n * @module Pict-Histogram-Renderer-ConsoleUI\n */\n\n/**\n * Build a vertical text histogram.\n *\n * Each column is one bar. Rows go from top (max value) to bottom (0).\n * Uses block characters for fractional rows.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The rendered text block\n */\nfunction renderVertical(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpHeight = tmpOptions.TextHeight || 15;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\tlet tmpEmptyChar = tmpOptions.EmptyCharacter;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\t// Determine label width for the value axis\n\tlet tmpValueAxisWidth = String(tmpMaxValue).length + 1;\n\n\t// Build the grid top-down\n\tlet tmpLines = [];\n\n\tfor (let tmpRow = tmpHeight; tmpRow >= 1; tmpRow--)\n\t{\n\t\tlet tmpLine = '';\n\n\t\t// Value axis label (only on a few rows)\n\t\tif (tmpRow === tmpHeight)\n\t\t{\n\t\t\ttmpLine += padLeft(String(tmpMaxValue), tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse if (tmpRow === 1)\n\t\t{\n\t\t\ttmpLine += padLeft('0', tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse if (tmpRow === Math.ceil(tmpHeight / 2))\n\t\t{\n\t\t\ttmpLine += padLeft(String(Math.round(tmpMaxValue / 2)), tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLine += padLeft('', tmpValueAxisWidth) + '|';\n\t\t}\n\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\t\tlet tmpBarHeight = (tmpVal / tmpMaxValue) * tmpHeight;\n\t\t\tlet tmpFullRows = Math.floor(tmpBarHeight);\n\t\t\tlet tmpFraction = tmpBarHeight - tmpFullRows;\n\n\t\t\tlet tmpChar = tmpEmptyChar;\n\t\t\tif (tmpRow <= tmpFullRows)\n\t\t\t{\n\t\t\t\ttmpChar = tmpBarChar;\n\t\t\t}\n\t\t\telse if (tmpRow === tmpFullRows + 1 && tmpFraction > 0)\n\t\t\t{\n\t\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\t\ttmpChar = tmpPartials[tmpPartialIndex];\n\t\t\t}\n\n\t\t\t// Mark selected bins\n\t\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\n\t\t\tif (tmpIsSelected && tmpChar !== tmpEmptyChar)\n\t\t\t{\n\t\t\t\ttmpChar = '*';\n\t\t\t}\n\t\t\telse if (tmpInRange && tmpChar !== tmpEmptyChar)\n\t\t\t{\n\t\t\t\ttmpChar = '#';\n\t\t\t}\n\n\t\t\t// Each bar is 3 chars wide with 1 char gap\n\t\t\ttmpLine += ' ' + tmpChar + tmpChar + tmpChar;\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Bottom axis\n\tlet tmpAxisLine = padLeft('', tmpValueAxisWidth) + '+';\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\ttmpAxisLine += '----';\n\t}\n\ttmpLines.push(tmpAxisLine);\n\n\t// Labels row\n\tif (tmpOptions.ShowLabels)\n\t{\n\t\tlet tmpLabelLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\t\ttmpLabelLine += padCenter(tmpLabel.substring(0, 4), 4);\n\t\t}\n\t\ttmpLines.push(tmpLabelLine);\n\t}\n\n\t// Selection range indicator\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpRangeLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tif (i === pView._selectionRangeStart)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' [ ';\n\t\t\t}\n\t\t\telse if (i === pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' ] ';\n\t\t\t}\n\t\t\telse if (i > pView._selectionRangeStart && i < pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' - ';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' ';\n\t\t\t}\n\t\t}\n\t\ttmpLines.push(tmpRangeLine);\n\t}\n\n\treturn tmpLines.join('\\n');\n}\n\n/**\n * Build a horizontal text histogram.\n *\n * Each row is one bar growing rightward.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The rendered text block\n */\nfunction renderHorizontal(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpWidth = tmpOptions.TextWidth || 60;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tlet tmpMaxLabelLen = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tif (tmpLabel.length > tmpMaxLabelLen)\n\t\t{\n\t\t\ttmpMaxLabelLen = tmpLabel.length;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpLabelWidth = Math.min(tmpMaxLabelLen, 12);\n\tlet tmpBarWidth = tmpWidth - tmpLabelWidth - 2; // space for \" |\"\n\tif (tmpBarWidth < 10)\n\t{\n\t\ttmpBarWidth = 10;\n\t}\n\n\tlet tmpLines = [];\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tlet tmpBarLen = (tmpVal / tmpMaxValue) * tmpBarWidth;\n\t\tlet tmpFullChars = Math.floor(tmpBarLen);\n\t\tlet tmpFraction = tmpBarLen - tmpFullChars;\n\n\t\tlet tmpBar = '';\n\t\tfor (let j = 0; j < tmpFullChars; j++)\n\t\t{\n\t\t\ttmpBar += tmpBarChar;\n\t\t}\n\t\tif (tmpFraction > 0 && tmpFullChars < tmpBarWidth)\n\t\t{\n\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\ttmpBar += tmpPartials[tmpPartialIndex];\n\t\t}\n\n\t\t// Mark selected\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\tlet tmpMarker = tmpIsSelected ? '*' : (tmpInRange ? '~' : '');\n\n\t\tlet tmpValueStr = tmpOptions.ShowValues ? (' ' + tmpVal) : '';\n\t\tlet tmpLine = padRight(tmpLabel.substring(0, tmpLabelWidth), tmpLabelWidth) + ' |' + tmpBar + tmpValueStr + tmpMarker;\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Range indicator for range selection\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\ttmpLines.push('');\n\t\ttmpLines.push(padRight('', tmpLabelWidth) + ' Range: [' + pView._selectionRangeStart + ' - ' + pView._selectionRangeEnd + ']');\n\t}\n\n\treturn tmpLines.join('\\n');\n}\n\n/**\n * Render via ContentAssignment for consoleui mode.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpText;\n\tif (pView.options.Orientation === 'vertical')\n\t{\n\t\ttmpText = renderVertical(pView);\n\t}\n\telse\n\t{\n\t\ttmpText = renderHorizontal(pView);\n\t}\n\n\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpText);\n}\n\n// No interactive events for consoleui — input is handled by the blessed widget layer\nfunction wireEvents()\n{\n\t// No-op for consoleui\n}\n\n// --- Utility ---\n\nfunction padLeft(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = ' ' + tmpStr;\n\t}\n\treturn tmpStr;\n}\n\nfunction padRight(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = tmpStr + ' ';\n\t}\n\treturn tmpStr;\n}\n\nfunction padCenter(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = (tmpStr.length % 2 === 0) ? (tmpStr + ' ') : (' ' + tmpStr);\n\t}\n\treturn tmpStr;\n}\n\nmodule.exports = { render, wireEvents, renderVertical, renderHorizontal };\n\n},{}],12:[function(require,module,exports){\nmodule.exports={\n \"name\": \"pict-view\",\n \"version\": \"1.0.67\",\n \"description\": \"Pict View Base Class\",\n \"main\": \"source/Pict-View.js\",\n \"scripts\": {\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"start\": \"node source/Pict-View.js\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-view-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-view-dev -p 30001:8080 -p 38086:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-view\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-view-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-view-dev /bin/bash\",\n \"types\": \"tsc -p .\",\n \"lint\": \"eslint source/**\"\n },\n \"types\": \"types/source/Pict-View.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-view.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-view/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-view#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.1\",\n \"browser-env\": \"^3.3.0\",\n \"eslint\": \"^9.39.1\",\n \"pict\": \"^1.0.348\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"dependencies\": {\n \"fable\": \"^3.1.63\",\n \"fable-serviceproviderbase\": \"^3.0.19\"\n }\n}\n\n},{}],13:[function(require,module,exports){\n\nconst libFableServiceBase = require('fable-serviceproviderbase');\n\nconst libPackage = require('../package.json');\n\nconst defaultPictViewSettings = (\n\t{\n\t\tDefaultRenderable: false,\n\t\tDefaultDestinationAddress: false,\n\t\tDefaultTemplateRecordAddress: false,\n\n\t\tViewIdentifier: false,\n\n\t\t// If this is set to true, when the App initializes this will.\n\t\t// After the App initializes, initialize will be called as soon as it's added.\n\t\tAutoInitialize: true,\n\t\tAutoInitializeOrdinal: 0,\n\n\t\t// If this is set to true, when the App autorenders (on load) this will.\n\t\t// After the App initializes, render will be called as soon as it's added.\n\t\tAutoRender: true,\n\t\tAutoRenderOrdinal: 0,\n\n\t\tAutoSolveWithApp: true,\n\t\tAutoSolveOrdinal: 0,\n\n\t\tCSSHash: false,\n\t\tCSS: false,\n\t\tCSSProvider: false,\n\t\tCSSPriority: 500,\n\n\t\tTemplates: [],\n\n\t\tDefaultTemplates: [],\n\n\t\tRenderables: [],\n\n\t\tManifests: {}\n\t});\n\n/** @typedef {(error?: Error) => void} ErrorCallback */\n/** @typedef {number | boolean} PictTimestamp */\n\n/**\n * @typedef {'replace' | 'append' | 'prepend' | 'append_once' | 'virtual-assignment'} RenderMethod\n */\n/**\n * @typedef {Object} Renderable\n *\n * @property {string} RenderableHash - A unique hash for the renderable.\n * @property {string} TemplateHash - The hash of the template to use for rendering this renderable.\n * @property {string} [DefaultTemplateRecordAddress] - The default address for resolving the data record for this renderable.\n * @property {string} [ContentDestinationAddress] - The default address (DOM CSS selector) for rendering the content of this renderable.\n * @property {RenderMethod} [RenderMethod=replace] - The method to use when projecting the renderable to the DOM ('replace', 'append', 'prepend', 'append_once', 'virtual-assignment').\n * @property {string} [TestAddress] - The address to use for testing the renderable.\n * @property {string} [TransactionHash] - The transaction hash for the root renderable.\n * @property {string} [RootRenderableViewHash] - The hash of the root renderable.\n * @property {string} [Content] - The rendered content for this renderable, if applicable.\n */\n\n/**\n * Represents a view in the Pict ecosystem.\n */\nclass PictView extends libFableServiceBase\n{\n\t/**\n\t * @param {any} pFable - The Fable object that this service is attached to.\n\t * @param {any} [pOptions] - (optional) The options for this service.\n\t * @param {string} [pServiceHash] - (optional) The hash of the service.\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t// Intersect default options, parent constructor, service information\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictViewSettings)), pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\t\t//FIXME: add types to fable and ancillaries\n\t\t/** @type {any} */\n\t\tthis.fable;\n\t\t/** @type {any} */\n\t\tthis.options;\n\t\t/** @type {String} */\n\t\tthis.UUID;\n\t\t/** @type {String} */\n\t\tthis.Hash;\n\t\t/** @type {any} */\n\t\tthis.log;\n\n\t\tconst tmpHashIsUUID = this.Hash === this.UUID;\n\t\t//NOTE: since many places are using the view UUID as the HTML element ID, we prefix it to avoid starting with a number\n\t\tthis.UUID = `V-${this.UUID}`;\n\t\tif (tmpHashIsUUID)\n\t\t{\n\t\t\tthis.Hash = this.UUID;\n\t\t}\n\n\t\tif (!this.options.ViewIdentifier)\n\t\t{\n\t\t\tthis.options.ViewIdentifier = `AutoViewID-${this.fable.getUUID()}`;\n\t\t}\n\t\tthis.serviceType = 'PictView';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\t\t// Convenience and consistency naming\n\t\t/** @type {import('pict') & { log: any, instantiateServiceProviderWithoutRegistration: (hash: String) => any, instantiateServiceProviderIfNotExists: (hash: string) => any, TransactionTracking: import('pict/types/source/services/Fable-Service-TransactionTracking') }} */\n\t\tthis.pict = this.fable;\n\t\t// Wire in the essential Pict application state\n\t\tthis.AppData = this.pict.AppData;\n\t\tthis.Bundle = this.pict.Bundle;\n\n\t\t/** @type {PictTimestamp} */\n\t\tthis.initializeTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastSolvedTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastRenderedTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastMarshalFromViewTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastMarshalToViewTimestamp = false;\n\n\t\tthis.pict.instantiateServiceProviderIfNotExists('TransactionTracking');\n\n\t\t// Load all templates from the array in the options\n\t\t// Templates are in the form of {Hash:'Some-Template-Hash',Template:'Template content',Source:'TemplateSource'}\n\t\tfor (let i = 0; i < this.options.Templates.length; i++)\n\t\t{\n\t\t\tlet tmpTemplate = this.options.Templates[i];\n\n\t\t\tif (!('Hash' in tmpTemplate) || !('Template' in tmpTemplate))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Template ${i} in the options array.`, tmpTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpTemplate.Source = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addTemplate(tmpTemplate.Hash, tmpTemplate.Template, tmpTemplate.Source);\n\t\t\t}\n\t\t}\n\n\t\t// Load all default templates from the array in the options\n\t\t// Templates are in the form of {Prefix:'',Postfix:'-List-Row',Template:'Template content',Source:'TemplateSourceString'}\n\t\tfor (let i = 0; i < this.options.DefaultTemplates.length; i++)\n\t\t{\n\t\t\tlet tmpDefaultTemplate = this.options.DefaultTemplates[i];\n\n\t\t\tif (!('Postfix' in tmpDefaultTemplate) || !('Template' in tmpDefaultTemplate))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Default Template ${i} in the options array.`, tmpDefaultTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpDefaultTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpDefaultTemplate.Source = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix, tmpDefaultTemplate.Postfix, tmpDefaultTemplate.Template, tmpDefaultTemplate.Source);\n\t\t\t}\n\t\t}\n\n\t\t// Load the CSS if it's available\n\t\tif (this.options.CSS)\n\t\t{\n\t\t\tlet tmpCSSHash = this.options.CSSHash ? this.options.CSSHash : `View-${this.options.ViewIdentifier}`;\n\t\t\tlet tmpCSSProvider = this.options.CSSProvider ? this.options.CSSProvider : tmpCSSHash;\n\t\t\tthis.pict.CSSMap.addCSS(tmpCSSHash, this.options.CSS, tmpCSSProvider, this.options.CSSPriority);\n\t\t}\n\n\t\t// Load all renderables\n\t\t// Renderables are launchable renderable instructions with templates\n\t\t// They look as such: {Identifier:'ContentEntry', TemplateHash:'Content-Entry-Section-Main', ContentDestinationAddress:'#ContentSection', RecordAddress:'AppData.Content.DefaultText', ManifestTransformation:'ManyfestHash', ManifestDestinationAddress:'AppData.Content.DataToTransformContent'}\n\t\t// The only parts that are necessary are Identifier and Template\n\t\t// A developer can then do render('ContentEntry') and it just kinda works. Or they can override the ContentDestinationAddress\n\t\t/** @type {Record<String, Renderable>} */\n\t\tthis.renderables = {};\n\t\tfor (let i = 0; i < this.options.Renderables.length; i++)\n\t\t{\n\t\t\t/** @type {Renderable} */\n\t\t\tlet tmpRenderable = this.options.Renderables[i];\n\t\t\tthis.addRenderable(tmpRenderable);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a renderable to the view.\n\t *\n\t * @param {string | Renderable} pRenderableHash - The hash of the renderable, or a renderable object.\n\t * @param {string} [pTemplateHash] - (optional) The hash of the template for the renderable.\n\t * @param {string} [pDefaultTemplateRecordAddress] - (optional) The default data address for the template.\n\t * @param {string} [pDefaultDestinationAddress] - (optional) The default destination address for the renderable.\n\t * @param {RenderMethod} [pRenderMethod=replace] - (optional) The method to use when rendering the renderable (ex. 'replace').\n\t */\n\taddRenderable(pRenderableHash, pTemplateHash, pDefaultTemplateRecordAddress, pDefaultDestinationAddress, pRenderMethod)\n\t{\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\n\t\tif (typeof(pRenderableHash) == 'object')\n\t\t{\n\t\t\t// The developer passed in the renderable as an object.\n\t\t\t// Use theirs instead!\n\t\t\ttmpRenderable = pRenderableHash;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/** @type {RenderMethod} */\n\t\t\tlet tmpRenderMethod = (typeof(pRenderMethod) !== 'string') ? pRenderMethod : 'replace';\n\t\t\ttmpRenderable = (\n\t\t\t\t{\n\t\t\t\t\tRenderableHash: pRenderableHash,\n\t\t\t\t\tTemplateHash: pTemplateHash,\n\t\t\t\t\tDefaultTemplateRecordAddress: pDefaultTemplateRecordAddress,\n\t\t\t\t\tContentDestinationAddress: pDefaultDestinationAddress,\n\t\t\t\t\tRenderMethod: tmpRenderMethod\n\t\t\t\t});\n\t\t}\n\n\t\tif ((typeof(tmpRenderable.RenderableHash) != 'string') || (typeof(tmpRenderable.TemplateHash) != 'string'))\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Renderable; RenderableHash or TemplateHash are invalid.`, tmpRenderable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} adding renderable [${tmpRenderable.RenderableHash}] pointed to template ${tmpRenderable.TemplateHash}.`);\n\t\t\t}\n\n\t\t\tthis.renderables[tmpRenderable.RenderableHash] = tmpRenderable;\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialization */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is initialized.\n\t */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is initialized.\n\t */\n\tonInitialize()\n\t{\n\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Performs view initialization.\n\t */\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\t\t\tthis.onInitialize();\n\t\t\tthis.onAfterInitialize();\n\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Performs view initialization (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initializeAsync:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.info(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} beginning initialization...`);\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t/** @param {Error} pError */\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialization failed: ${pError.message || pError}`, { stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.info(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fCallback();\n\t\t\t\t});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn fCallback();\n\t\t}\n\t}\n\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Render */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is rendered.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that will be rendered.\n\t */\n\tonBeforeRender(pRenderable)\n\t{\n\t\t// Overload this to mess with stuff before the content gets generated from the template\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is rendered (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that will be rendered.\n\t */\n\tonBeforeRenderAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onBeforeRender(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is projected into the DOM.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that will be projected.\n\t */\n\tonBeforeProject(pRenderable)\n\t{\n\t\t// Overload this to mess with stuff before the content gets generated from the template\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeProject:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is projected into the DOM (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that will be projected.\n\t */\n\tonBeforeProjectAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onBeforeProject(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Builds the render options for a renderable.\n\t *\n\t * For DRY purposes on the three flavors of render.\n\t *\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbuildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\tlet tmpRenderOptions = {Valid: true};\n\t\ttmpRenderOptions.RenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t\t\t\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ?\n\t\t\t\t\t\t\t\tthis.options.DefaultRenderable : false;\n\t\tif (!tmpRenderOptions.RenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not find a suitable RenderableHash ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\ttmpRenderOptions.Renderable = this.renderables[tmpRenderOptions.RenderableHash];\n\t\tif (!tmpRenderOptions.Renderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\ttmpRenderOptions.DestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t(typeof (tmpRenderOptions.Renderable.ContentDestinationAddress) === 'string') ? tmpRenderOptions.Renderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : false;\n\t\tif (!tmpRenderOptions.DestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address (param ${pRenderDestinationAddress}).`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRenderOptions.RecordAddress = 'Passed in as object';\n\t\t\ttmpRenderOptions.Record = pTemplateRecordAddress;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderOptions.RecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderOptions.Renderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderOptions.Renderable.DefaultTemplateRecordAddress :\n\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\t\t\ttmpRenderOptions.Record = (typeof (tmpRenderOptions.RecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRenderOptions.RecordAddress) : undefined;\n\t\t}\n\n\t\treturn tmpRenderOptions;\n\t}\n\n\t/**\n\t * Assigns the content to the destination address.\n\t *\n\t * For DRY purposes on the three flavors of render.\n\t *\n\t * @param {Renderable} pRenderable - The renderable to render.\n\t * @param {string} pRenderDestinationAddress - The address where the renderable will be rendered.\n\t * @param {string} pContent - The content to render.\n\t * @returns {boolean} - Returns true if the content was assigned successfully.\n\t * @memberof PictView\n\t */\n\tassignRenderContent(pRenderable, pRenderDestinationAddress, pContent)\n\t{\n\t\treturn this.pict.ContentAssignment.projectContent(pRenderable.RenderMethod, pRenderDestinationAddress, pContent, pRenderable.TestAddress);\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @return {boolean}\n\t */\n\trender(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable)\n\t{\n\t\treturn this.renderWithScope(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable);\n\t}\n\n\t/**\n\t * Render a renderable from this view, providing a specifici scope for the template.\n\t *\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @return {boolean}\n\t */\n\trenderWithScope(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable)\n\t{\n\t\tlet tmpRenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ? this.options.DefaultRenderable : false;\n\t\tif (!tmpRenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it is not a valid renderable.`);\n\t\t\treturn false;\n\t\t}\n\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\t\tif (tmpRenderableHash == '__Virtual')\n\t\t{\n\t\t\ttmpRenderable = {\n\t\t\t\tRenderableHash: '__Virtual',\n\t\t\t\tTemplateHash: this.renderables[this.options.DefaultRenderable].TemplateHash,\n\t\t\t\tContentDestinationAddress: (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null,\n\t\t\t\tRenderMethod: 'virtual-assignment',\n\t\t\t\tTransactionHash: pRootRenderable && pRootRenderable.TransactionHash,\n\t\t\t\tRootRenderableViewHash: pRootRenderable && pRootRenderable.RootRenderableViewHash,\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderable = Object.assign({}, this.renderables[tmpRenderableHash]);\n\t\t\ttmpRenderable.ContentDestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null;\n\t\t}\n\n\t\tif (!tmpRenderable.TransactionHash)\n\t\t{\n\t\t\ttmpRenderable.TransactionHash = `ViewRender-V-${this.options.ViewIdentifier}-R-${tmpRenderableHash}-U-${this.pict.getUUID()}`;\n\t\t\ttmpRenderable.RootRenderableViewHash = this.Hash;\n\t\t\tthis.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);\n\t\t}\n\n\t\tif (!tmpRenderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!tmpRenderable.ContentDestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tlet tmpRecordAddress;\n\t\tlet tmpRecord;\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRecord = pTemplateRecordAddress;\n\t\t\ttmpRecordAddress = 'Passed in as object';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderable.DefaultTemplateRecordAddress :\n\t\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\n\t\t\ttmpRecord = (typeof (tmpRecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRecordAddress) : undefined;\n\t\t}\n\n\t\t// Execute the developer-overridable pre-render behavior\n\t\tthis.onBeforeRender(tmpRenderable);\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] Renderable[${tmpRenderableHash}] Destination[${tmpRenderable.ContentDestinationAddress}] TemplateRecordAddress[${tmpRecordAddress}] render:`);\n\t\t}\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Beginning Render of Renderable[${tmpRenderableHash}] to Destination [${tmpRenderable.ContentDestinationAddress}]...`);\n\t\t}\n\t\t// Generate the content output from the template and data\n\t\ttmpRenderable.Content = this.pict.parseTemplateByHash(tmpRenderable.TemplateHash, tmpRecord, null, [this], pScope, { RootRenderable: typeof pRootRenderable === 'object' ? pRootRenderable : tmpRenderable });\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Assigning Renderable[${tmpRenderableHash}] content length ${tmpRenderable.Content.length} to Destination [${tmpRenderable.ContentDestinationAddress}] using render method [${tmpRenderable.RenderMethod}].`);\n\t\t}\n\n\t\tthis.onBeforeProject(tmpRenderable);\n\t\tthis.onProject(tmpRenderable);\n\n\t\tif (tmpRenderable.RenderMethod !== 'virtual-assignment')\n\t\t{\n\t\t\tthis.onAfterProject(tmpRenderable);\n\n\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\tthis.onAfterRender(tmpRenderable);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t *\n\t * @return {void}\n\t */\n\trenderAsync(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback)\n\t{\n\t\treturn this.renderWithScopeAsync(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback);\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t *\n\t * @return {void}\n\t */\n\trenderWithScopeAsync(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback)\n\t{\n\t\tlet tmpRenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ? this.options.DefaultRenderable : false;\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateRecordAddress) === 'function') ? pTemplateRecordAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\t(typeof(pRootRenderable) === 'function') ? pRootRenderable :\n\t\t\t\t\t\t\tnull;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (!tmpRenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not asynchronously render ${tmpRenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`);\n\t\t\treturn tmpCallback(new Error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not asynchronously render ${tmpRenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`));\n\t\t}\n\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\t\tif (tmpRenderableHash == '__Virtual')\n\t\t{\n\t\t\ttmpRenderable = {\n\t\t\t\tRenderableHash: '__Virtual',\n\t\t\t\tTemplateHash: this.renderables[this.options.DefaultRenderable].TemplateHash,\n\t\t\t\tContentDestinationAddress: (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress : (typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null,\n\t\t\t\tRenderMethod: 'virtual-assignment',\n\t\t\t\tTransactionHash: pRootRenderable && typeof pRootRenderable !== 'function' && pRootRenderable.TransactionHash,\n\t\t\t\tRootRenderableViewHash: pRootRenderable && typeof pRootRenderable !== 'function' && pRootRenderable.RootRenderableViewHash,\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderable = Object.assign({}, this.renderables[tmpRenderableHash]);\n\t\t\ttmpRenderable.ContentDestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null;\n\t\t}\n\n\t\tif (!tmpRenderable.TransactionHash)\n\t\t{\n\t\t\ttmpRenderable.TransactionHash = `ViewRender-V-${this.options.ViewIdentifier}-R-${tmpRenderableHash}-U-${this.pict.getUUID()}`;\n\t\t\ttmpRenderable.RootRenderableViewHash = this.Hash;\n\t\t\tthis.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);\n\t\t}\n\n\t\tif (!tmpRenderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\treturn tmpCallback(new Error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`));\n\t\t}\n\n\t\tif (!tmpRenderable.ContentDestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address.`);\n\t\t\treturn tmpCallback(new Error(`Could not render ${tmpRenderableHash}`));\n\t\t}\n\n\t\tlet tmpRecordAddress;\n\t\tlet tmpRecord;\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRecord = pTemplateRecordAddress;\n\t\t\ttmpRecordAddress = 'Passed in as object';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderable.DefaultTemplateRecordAddress :\n\t\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\n\t\t\ttmpRecord = (typeof (tmpRecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRecordAddress) : undefined;\n\t\t}\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] Renderable[${tmpRenderableHash}] Destination[${tmpRenderable.ContentDestinationAddress}] TemplateRecordAddress[${tmpRecordAddress}] renderAsync:`);\n\t\t}\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Beginning Asynchronous Render (callback-style)...`);\n\t\t}\n\n\t\tlet tmpAnticipate = this.fable.newAnticipate();\n\n\t\ttmpAnticipate.anticipate(\n\t\t\t(fOnBeforeRenderCallback) =>\n\t\t\t{\n\t\t\t\tthis.onBeforeRenderAsync(fOnBeforeRenderCallback, tmpRenderable);\n\t\t\t});\n\n\t\ttmpAnticipate.anticipate(\n\t\t\t(fAsyncTemplateCallback) =>\n\t\t\t{\n\t\t\t\t// Render the template (asynchronously)\n\t\t\t\tthis.pict.parseTemplateByHash(tmpRenderable.TemplateHash, tmpRecord,\n\t\t\t\t\t(pError, pContent) =>\n\t\t\t\t\t{\n\t\t\t\t\t\tif (pError)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render (asynchronously) ${tmpRenderableHash} (param ${pRenderableHash}) because it did not parse the template.`, pError);\n\t\t\t\t\t\t\treturn fAsyncTemplateCallback(pError);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttmpRenderable.Content = pContent;\n\n\t\t\t\t\t\treturn fAsyncTemplateCallback();\n\t\t\t\t\t}, [this], pScope, { RootRenderable: typeof pRootRenderable === 'object' ? pRootRenderable : tmpRenderable });\n\t\t\t});\n\n\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t{\n\t\t\tthis.onBeforeProjectAsync(fNext, tmpRenderable);\n\t\t});\n\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t{\n\t\t\tthis.onProjectAsync(fNext, tmpRenderable);\n\t\t});\n\n\t\tif (tmpRenderable.RenderMethod !== 'virtual-assignment')\n\t\t{\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tthis.onAfterProjectAsync(fNext, tmpRenderable);\n\t\t\t});\n\n\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tthis.onAfterRenderAsync(fNext, tmpRenderable);\n\t\t\t});\n\t\t}\n\n\t\ttmpAnticipate.wait(tmpCallback);\n\t}\n\n\t/**\n\t * Renders the default renderable.\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\trenderDefaultAsync(fCallback)\n\t{\n\t\t// Render the default renderable\n\t\tthis.renderAsync(fCallback);\n\t}\n\n\t/**\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbasicRender(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\treturn this.basicRenderWithScope(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t}\n\n\t/**\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbasicRenderWithScope(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\tlet tmpRenderOptions = this.buildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t\tif (tmpRenderOptions.Valid)\n\t\t{\n\t\t\tthis.assignRenderContent(tmpRenderOptions.Renderable, tmpRenderOptions.DestinationAddress, this.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash, tmpRenderOptions.Record, null, [this], pScope, { RootRenderable: tmpRenderOptions.Renderable }));\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not perform a basic render of ${tmpRenderOptions.RenderableHash} because it is not valid.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t */\n\tbasicRenderAsync(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback)\n\t{\n\t\treturn this.basicRenderWithScopeAsync(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback);\n\t}\n\n\t/**\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t */\n\tbasicRenderWithScopeAsync(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback)\n\t{\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateRecordAddress) === 'function') ? pTemplateRecordAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\tnull;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} basicRenderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} basicRenderAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tconst tmpRenderOptions = this.buildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t\tif (tmpRenderOptions.Valid)\n\t\t{\n\t\t\tthis.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash, tmpRenderOptions.Record,\n\t\t\t\t/**\n\t\t\t\t * @param {Error} [pError] - The error that occurred during template parsing.\n\t\t\t\t * @param {string} [pContent] - The content that was rendered from the template.\n\t\t\t\t */\n\t\t\t\t(pError, pContent) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render (asynchronously) ${tmpRenderOptions.RenderableHash} because it did not parse the template.`, pError);\n\t\t\t\t\t\treturn tmpCallback(pError);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.assignRenderContent(tmpRenderOptions.Renderable, tmpRenderOptions.DestinationAddress, pContent);\n\t\t\t\t\treturn tmpCallback();\n\t\t\t\t}, [this], pScope, { RootRenderable: tmpRenderOptions.Renderable });\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpErrorMessage = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not perform a basic render of ${tmpRenderOptions.RenderableHash} because it is not valid.`;\n\t\t\tthis.log.error(tmpErrorMessage);\n\t\t\treturn tmpCallback(new Error(tmpErrorMessage));\n\t\t}\n\t}\n\n\t/**\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonProject(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onProject:`);\n\t\t}\n\t\tif (pRenderable.RenderMethod === 'virtual-assignment')\n\t\t{\n\t\t\tthis.pict.TransactionTracking.pushToTransactionQueue(pRenderable.TransactionHash, { ViewHash: this.Hash, Renderable: pRenderable }, 'Deferred-Post-Content-Assignment');\n\t\t}\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Assigning Renderable[${pRenderable.RenderableHash}] content length ${pRenderable.Content.length} to Destination [${pRenderable.ContentDestinationAddress}] using Async render method ${pRenderable.RenderMethod}.`);\n\t\t}\n\n\t\t// Assign the content to the destination address\n\t\tthis.pict.ContentAssignment.projectContent(pRenderable.RenderMethod, pRenderable.ContentDestinationAddress, pRenderable.Content, pRenderable.TestAddress);\n\n\t\tthis.lastRenderedTimestamp = this.pict.log.getTimeStamp();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM (async flow).\n\t *\n\t * @param {(error?: Error, content?: string) => void} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that is being projected.\n\t */\n\tonProjectAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onProject(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is rendered.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonAfterRender(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRender:`);\n\t\t}\n\t\tif (pRenderable && pRenderable.RootRenderableViewHash === this.Hash)\n\t\t{\n\t\t\tconst tmpTransactionQueue = this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash) || [];\n\t\t\tfor (const tmpEvent of tmpTransactionQueue)\n\t\t\t{\n\t\t\t\tconst tmpView = this.pict.views[tmpEvent.Data.ViewHash];\n\t\t\t\tif (!tmpView)\n\t\t\t\t{\n\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRender: Could not find view for transaction hash ${pRenderable.TransactionHash} and ViewHash ${tmpEvent.Data.ViewHash}.`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttmpView.onAfterProject();\n\n\t\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\t\ttmpView.onAfterRender(tmpEvent.Data.Renderable);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is rendered (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonAfterRenderAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onAfterRender(pRenderable);\n\t\tconst tmpAnticipate = this.fable.newAnticipate();\n\t\tif (pRenderable && pRenderable.RootRenderableViewHash === this.Hash)\n\t\t{\n\t\t\tconst queue = this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash) || [];\n\t\t\tfor (const event of queue)\n\t\t\t{\n\t\t\t\t/** @type {PictView} */\n\t\t\t\tconst tmpView = this.pict.views[event.Data.ViewHash];\n\t\t\t\tif (!tmpView)\n\t\t\t\t{\n\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRenderAsync: Could not find view for transaction hash ${pRenderable.TransactionHash} and ViewHash ${event.Data.ViewHash}.`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(tmpView.onAfterProjectAsync.bind(tmpView));\n\t\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t\t{\n\t\t\t\t\ttmpView.onAfterRenderAsync(fNext, event.Data.Renderable);\n\t\t\t\t});\n\n\t\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\t}\n\t\t}\n\t\treturn tmpAnticipate.wait(fCallback);\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that was projected.\n\t */\n\tonAfterProject(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterProject:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that was projected.\n\t */\n\tonAfterProjectAsync(fCallback, pRenderable)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Solver */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is solved.\n\t */\n\tonBeforeSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeSolveAsync(fCallback)\n\t{\n\t\tthis.onBeforeSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is solved.\n\t */\n\tonSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonSolveAsync(fCallback)\n\t{\n\t\tthis.onSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Performs view solving and triggers lifecycle hooks.\n\t *\n\t * @return {boolean} - True if the view was solved successfully, false otherwise.\n\t */\n\tsolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeSolve();\n\t\tthis.onSolve();\n\t\tthis.onAfterSolve();\n\t\tthis.lastSolvedTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Performs view solving and triggers lifecycle hooks (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} solveAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSolvedTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is solved.\n\t */\n\tonAfterSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterSolveAsync(fCallback)\n\t{\n\t\tthis.onAfterSolve();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal From View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled from the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tonBeforeMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeMarshalFromViewAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled from the view.\n\t */\n\tonMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonMarshalFromViewAsync(fCallback)\n\t{\n\n\t\tthis.onMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Marshals data from the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tmarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeMarshalFromView();\n\t\tthis.onMarshalFromView();\n\t\tthis.onAfterMarshalFromView();\n\t\tthis.lastMarshalFromViewTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Marshals data from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tmarshalFromViewAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalFromViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onMarshalFromViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalFromViewAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} marshalFromViewAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalFromViewTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled from the view.\n\t */\n\tonAfterMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterMarshalFromViewAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal To View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled into the view.\n\t */\n\tonBeforeMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled into the view.\n\t */\n\tonMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Marshals data into the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tmarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeMarshalToView();\n\t\tthis.onMarshalToView();\n\t\tthis.onAfterMarshalToView();\n\t\tthis.lastMarshalToViewTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Marshals data into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tmarshalToViewAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalToViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onMarshalToViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalToViewAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} marshalToViewAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalToViewTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled into the view.\n\t */\n\tonAfterMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/** @return {boolean} - True if the object is a PictView. */\n\tget isPictView()\n\t{\n\t\treturn true;\n\t}\n}\n\nmodule.exports = PictView;\n\n},{\"../package.json\":12,\"fable-serviceproviderbase\":2}],14:[function(require,module,exports){\n// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n\n},{}],15:[function(require,module,exports){\nmodule.exports={\n\t\"Name\": \"Retold Data Cloner\",\n\t\"Hash\": \"DataCloner\",\n\t\"MainViewportViewIdentifier\": \"DataCloner-Layout\",\n\t\"MainViewportDestinationAddress\": \"#DataCloner-Application-Container\",\n\t\"MainViewportDefaultDataAddress\": \"AppData.DataCloner\",\n\t\"pict_configuration\": { \"Product\": \"DataCloner\" },\n\t\"AutoRenderMainViewportViewAfterInitialize\": false\n}\n\n},{}],16:[function(require,module,exports){\nconst libPictApplication = require('pict-application');\n\nconst libProvider = require('./providers/Pict-Provider-DataCloner.js');\n\nconst libViewLayout = require('./views/PictView-DataCloner-Layout.js');\nconst libViewConnection = require('./views/PictView-DataCloner-Connection.js');\nconst libViewSession = require('./views/PictView-DataCloner-Session.js');\nconst libViewSchema = require('./views/PictView-DataCloner-Schema.js');\nconst libViewDeploy = require('./views/PictView-DataCloner-Deploy.js');\nconst libViewSync = require('./views/PictView-DataCloner-Sync.js');\nconst libViewExport = require('./views/PictView-DataCloner-Export.js');\nconst libViewViewData = require('./views/PictView-DataCloner-ViewData.js');\nconst libViewHistogram = require('pict-section-histogram');\n\nclass DataClonerApplication extends libPictApplication\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\n\t\t// Register provider\n\t\tthis.pict.addProvider('DataCloner', libProvider.default_configuration, libProvider);\n\n\t\t// Register views\n\t\tthis.pict.addView('DataCloner-Layout', libViewLayout.default_configuration, libViewLayout);\n\t\tthis.pict.addView('DataCloner-Connection', libViewConnection.default_configuration, libViewConnection);\n\t\tthis.pict.addView('DataCloner-Session', libViewSession.default_configuration, libViewSession);\n\t\tthis.pict.addView('DataCloner-Schema', libViewSchema.default_configuration, libViewSchema);\n\t\tthis.pict.addView('DataCloner-Deploy', libViewDeploy.default_configuration, libViewDeploy);\n\t\tthis.pict.addView('DataCloner-Sync', libViewSync.default_configuration, libViewSync);\n\t\tthis.pict.addView('DataCloner-Export', libViewExport.default_configuration, libViewExport);\n\t\tthis.pict.addView('DataCloner-ViewData', libViewViewData.default_configuration, libViewViewData);\n\t\tthis.pict.addView('DataCloner-StatusHistogram',\n\t\t\t{\n\t\t\t\tViewIdentifier: 'DataCloner-StatusHistogram',\n\t\t\t\tTargetElementAddress: '#DataCloner-Throughput-Histogram',\n\t\t\t\tDefaultDestinationAddress: '#DataCloner-Throughput-Histogram',\n\t\t\t\tRenderOnLoad: false,\n\t\t\t\tSelectable: false,\n\t\t\t\tOrientation: 'vertical',\n\t\t\t\tFillContainer: true,\n\t\t\t\tShowValues: false,\n\t\t\t\tShowLabels: true,\n\t\t\t\tMaxBarSize: 80,\n\t\t\t\tBarColor: '#4a90d9',\n\t\t\t\tBins: []\n\t\t\t}, libViewHistogram);\n\t}\n\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\t// Centralized state (replaces global variables)\n\t\tthis.pict.AppData.DataCloner =\n\t\t{\n\t\t\tFetchedTables: [],\n\t\t\tDeployedTables: [],\n\t\t\tLastReport: null,\n\t\t\tServerBusyAtLoad: false,\n\t\t\tSyncPollTimer: null,\n\t\t\tLiveStatusTimer: null,\n\t\t\tStatusDetailExpanded: false,\n\t\t\tStatusDetailTimer: null,\n\t\t\tStatusDetailData: null,\n\t\t\tLastLiveStatus: null,\n\t\t\tPersistFields: [\n\t\t\t\t'serverURL', 'authMethod', 'authURI', 'checkURI',\n\t\t\t\t'cookieName', 'cookieValueAddr', 'cookieValueTemplate', 'loginMarker',\n\t\t\t\t'userName', 'password', 'schemaURL', 'pageSize', 'dateTimePrecisionMS',\n\t\t\t\t'connProvider', 'sqliteFilePath',\n\t\t\t\t'mysqlServer', 'mysqlPort', 'mysqlUser', 'mysqlPassword', 'mysqlDatabase', 'mysqlConnectionLimit',\n\t\t\t\t'mssqlServer', 'mssqlPort', 'mssqlUser', 'mssqlPassword', 'mssqlDatabase', 'mssqlConnectionLimit',\n\t\t\t\t'postgresqlHost', 'postgresqlPort', 'postgresqlUser', 'postgresqlPassword', 'postgresqlDatabase', 'postgresqlConnectionLimit',\n\t\t\t\t'solrHost', 'solrPort', 'solrCore', 'solrPath',\n\t\t\t\t'mongodbHost', 'mongodbPort', 'mongodbUser', 'mongodbPassword', 'mongodbDatabase', 'mongodbConnectionLimit',\n\t\t\t\t'rocksdbFolder',\n\t\t\t\t'bibliographFolder',\n\t\t\t\t'syncMaxRecords'\n\t\t\t]\n\t\t};\n\n\t\t// Make pict available for inline onclick handlers\n\t\twindow.pict = this.pict;\n\n\t\t// Render layout (which chains child view renders via onAfterRender)\n\t\tthis.pict.views['DataCloner-Layout'].render();\n\n\t\t// Post-render initialization\n\t\tthis.pict.providers.DataCloner.initPersistence();\n\t\tthis.pict.views['DataCloner-Connection'].onProviderChange();\n\t\tthis.pict.providers.DataCloner.restoreDeployedTables();\n\t\tthis.pict.providers.DataCloner.startLiveStatusPolling();\n\t\tthis.pict.providers.DataCloner.initAccordionPreviews();\n\t\tthis.pict.providers.DataCloner.updateAllPreviews();\n\t\tthis.pict.views['DataCloner-Layout'].collapseAllSections();\n\t\tthis.pict.providers.DataCloner.initAutoProcess();\n\n\t\treturn fCallback();\n\t}\n}\n\nmodule.exports = DataClonerApplication;\n\nmodule.exports.default_configuration = require('./Pict-Application-DataCloner-Configuration.json');\n\n},{\"./Pict-Application-DataCloner-Configuration.json\":15,\"./providers/Pict-Provider-DataCloner.js\":18,\"./views/PictView-DataCloner-Connection.js\":19,\"./views/PictView-DataCloner-Deploy.js\":20,\"./views/PictView-DataCloner-Export.js\":21,\"./views/PictView-DataCloner-Layout.js\":22,\"./views/PictView-DataCloner-Schema.js\":23,\"./views/PictView-DataCloner-Session.js\":24,\"./views/PictView-DataCloner-Sync.js\":25,\"./views/PictView-DataCloner-ViewData.js\":26,\"pict-application\":4,\"pict-section-histogram\":8}],17:[function(require,module,exports){\nmodule.exports = { DataClonerApplication: require('./Pict-Application-DataCloner.js') };\n\nif (typeof(window) !== 'undefined')\n{\n\twindow.DataClonerApplication = module.exports.DataClonerApplication;\n}\n\n},{\"./Pict-Application-DataCloner.js\":16}],18:[function(require,module,exports){\nconst libPictProvider = require('pict-provider');\n\nclass DataClonerProvider extends libPictProvider\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\t// ================================================================\n\t// API Helper\n\t// ================================================================\n\n\tapi(pMethod, pPath, pBody)\n\t{\n\t\tlet tmpOpts = { method: pMethod, headers: {} };\n\t\tif (pBody)\n\t\t{\n\t\t\ttmpOpts.headers['Content-Type'] = 'application/json';\n\t\t\ttmpOpts.body = JSON.stringify(pBody);\n\t\t}\n\t\treturn fetch(pPath, tmpOpts).then(function(pResponse) { return pResponse.json(); });\n\t}\n\n\tsetStatus(pElementId, pMessage, pType)\n\t{\n\t\tlet tmpEl = document.getElementById(pElementId);\n\t\tif (!tmpEl) return;\n\t\ttmpEl.className = 'status ' + (pType || 'info');\n\t\ttmpEl.textContent = pMessage;\n\t\ttmpEl.style.display = 'block';\n\t}\n\n\tescapeHtml(pStr)\n\t{\n\t\tlet tmpDiv = document.createElement('div');\n\t\ttmpDiv.appendChild(document.createTextNode(pStr));\n\t\treturn tmpDiv.innerHTML;\n\t}\n\n\t// ================================================================\n\t// Phase status indicators\n\t// ================================================================\n\n\tsetSectionPhase(pSection, pState)\n\t{\n\t\tlet tmpEl = document.getElementById('phase' + pSection);\n\t\tif (!tmpEl) return;\n\n\t\ttmpEl.className = 'accordion-phase';\n\n\t\tif (pState === 'ok')\n\t\t{\n\t\t\ttmpEl.innerHTML = '✓';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-ok');\n\t\t}\n\t\telse if (pState === 'error')\n\t\t{\n\t\t\ttmpEl.innerHTML = '✗';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-error');\n\t\t}\n\t\telse if (pState === 'busy')\n\t\t{\n\t\t\ttmpEl.innerHTML = '<span class=\"phase-spinner\"></span>';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-busy');\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpEl.innerHTML = '';\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Accordion Previews\n\t// ================================================================\n\n\tupdateAllPreviews()\n\t{\n\t\t// Section 1 — Database Connection\n\t\tlet tmpProvider = document.getElementById('connProvider');\n\t\tif (!tmpProvider) return;\n\t\ttmpProvider = tmpProvider.value;\n\t\tlet tmpPreview1 = tmpProvider;\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\tlet tmpPath = document.getElementById('sqliteFilePath').value || 'data/cloned.sqlite';\n\t\t\ttmpPreview1 = 'SQLite at ' + tmpPath;\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mysqlServer').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mysqlPort').value || '3306';\n\t\t\tlet tmpUser = document.getElementById('mysqlUser').value || 'root';\n\t\t\ttmpPreview1 = 'MySQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mssqlServer').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mssqlPort').value || '1433';\n\t\t\tlet tmpUser = document.getElementById('mssqlUser').value || 'sa';\n\t\t\ttmpPreview1 = 'MSSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('postgresqlHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('postgresqlPort').value || '5432';\n\t\t\tlet tmpUser = document.getElementById('postgresqlUser').value || 'postgres';\n\t\t\ttmpPreview1 = 'PostgreSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'MongoDB')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mongodbHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mongodbPort').value || '27017';\n\t\t\ttmpPreview1 = 'MongoDB on ' + tmpHost + ':' + tmpPort;\n\t\t}\n\t\telse if (tmpProvider === 'Solr')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('solrHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('solrPort').value || '8983';\n\t\t\ttmpPreview1 = 'Solr on ' + tmpHost + ':' + tmpPort;\n\t\t}\n\t\telse if (tmpProvider === 'RocksDB')\n\t\t{\n\t\t\tlet tmpFolder = document.getElementById('rocksdbFolder').value || 'data/rocksdb';\n\t\t\ttmpPreview1 = 'RocksDB at ' + tmpFolder;\n\t\t}\n\t\telse if (tmpProvider === 'Bibliograph')\n\t\t{\n\t\t\tlet tmpFolder = document.getElementById('bibliographFolder').value || 'data/bibliograph';\n\t\t\ttmpPreview1 = 'Bibliograph at ' + tmpFolder;\n\t\t}\n\t\tdocument.getElementById('preview1').textContent = tmpPreview1;\n\n\t\t// Section 2 — Remote Session\n\t\tlet tmpServerURL = document.getElementById('serverURL').value;\n\t\tlet tmpUserName = document.getElementById('userName').value;\n\t\tif (tmpServerURL)\n\t\t{\n\t\t\tlet tmpPreview2 = tmpServerURL;\n\t\t\tif (tmpUserName) tmpPreview2 += ' as ' + tmpUserName;\n\t\t\tdocument.getElementById('preview2').textContent = tmpPreview2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview2').textContent = 'Configure remote server URL and credentials';\n\t\t}\n\n\t\t// Section 3 — Remote Schema\n\t\tlet tmpTableChecks = document.querySelectorAll('#tableList input[type=\"checkbox\"]:checked');\n\t\tif (tmpTableChecks.length > 0)\n\t\t{\n\t\t\tdocument.getElementById('preview3').textContent = tmpTableChecks.length + ' table' + (tmpTableChecks.length === 1 ? '' : 's') + ' selected';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value;\n\t\t\tif (tmpSchemaURL)\n\t\t\t{\n\t\t\t\tdocument.getElementById('preview3').textContent = 'Schema from ' + tmpSchemaURL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById('preview3').textContent = 'Fetch and select tables from the remote server';\n\t\t\t}\n\t\t}\n\n\t\t// Section 4 — Deploy Schema\n\t\tlet tmpDeployedEl = document.getElementById('deployStatus');\n\t\tlet tmpDeployedText = tmpDeployedEl ? tmpDeployedEl.textContent : '';\n\t\tif (tmpDeployedText && tmpDeployedText.indexOf('deployed') !== -1)\n\t\t{\n\t\t\tdocument.getElementById('preview4').textContent = tmpDeployedText;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview4').textContent = 'Create selected tables in the local database';\n\t\t}\n\n\t\t// Section 5 — Synchronize Data\n\t\tlet tmpSyncMode = document.querySelector('input[name=\"syncMode\"]:checked');\n\t\tlet tmpModeName = tmpSyncMode ? tmpSyncMode.value : 'Initial';\n\t\tlet tmpPageSize = document.getElementById('pageSize').value || '100';\n\t\tlet tmpSyncPreview = tmpModeName + ' sync, page size ' + tmpPageSize;\n\t\tlet tmpDeleted = document.getElementById('syncDeletedRecords').checked;\n\t\tif (tmpDeleted) tmpSyncPreview += ', including deleted';\n\t\tdocument.getElementById('preview5').textContent = tmpSyncPreview;\n\n\t\t// Section 6 — Export Configuration\n\t\tlet tmpMaxRecords = document.getElementById('syncMaxRecords').value;\n\t\tlet tmpLogFile = document.getElementById('syncLogFile').checked;\n\t\tlet tmpExportParts = [];\n\t\tif (tmpMaxRecords && parseInt(tmpMaxRecords, 10) > 0) tmpExportParts.push('max ' + tmpMaxRecords + ' records');\n\t\tif (tmpLogFile) tmpExportParts.push('log enabled');\n\t\telse tmpExportParts.push('log disabled');\n\t\tdocument.getElementById('preview6').textContent = tmpExportParts.length > 0 ? 'Export: ' + tmpExportParts.join(', ') : 'Generate JSON config for headless cloning';\n\n\t\t// Section 7 — View Data\n\t\tlet tmpViewTable = document.getElementById('viewTable').value;\n\t\tif (tmpViewTable)\n\t\t{\n\t\t\tdocument.getElementById('preview7').textContent = 'Viewing ' + tmpViewTable;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview7').textContent = 'Browse synced table data';\n\t\t}\n\t}\n\n\tinitAccordionPreviews()\n\t{\n\t\tlet tmpSelf = this;\n\n\t\tlet tmpPreviewFields = [\n\t\t\t'connProvider', 'sqliteFilePath',\n\t\t\t'mysqlServer', 'mysqlPort', 'mysqlUser',\n\t\t\t'mssqlServer', 'mssqlPort', 'mssqlUser',\n\t\t\t'postgresqlHost', 'postgresqlPort', 'postgresqlUser',\n\t\t\t'mongodbHost', 'mongodbPort',\n\t\t\t'solrHost', 'solrPort',\n\t\t\t'rocksdbFolder', 'bibliographFolder',\n\t\t\t'serverURL', 'userName',\n\t\t\t'schemaURL',\n\t\t\t'pageSize', 'dateTimePrecisionMS',\n\t\t\t'syncMaxRecords',\n\t\t\t'viewTable', 'viewLimit'\n\t\t];\n\n\t\tlet tmpHandler = function() { tmpSelf.updateAllPreviews(); };\n\n\t\tfor (let i = 0; i < tmpPreviewFields.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById(tmpPreviewFields[i]);\n\t\t\tif (tmpEl)\n\t\t\t{\n\t\t\t\ttmpEl.addEventListener('input', tmpHandler);\n\t\t\t\ttmpEl.addEventListener('change', tmpHandler);\n\t\t\t}\n\t\t}\n\n\t\t// Checkboxes and radios\n\t\tlet tmpCheckboxes = ['syncDeletedRecords', 'syncLogFile'];\n\t\tfor (let i = 0; i < tmpCheckboxes.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById(tmpCheckboxes[i]);\n\t\t\tif (tmpEl) tmpEl.addEventListener('change', tmpHandler);\n\t\t}\n\n\t\tdocument.querySelectorAll('input[name=\"syncMode\"]').forEach(function(pEl)\n\t\t{\n\t\t\tpEl.addEventListener('change', tmpHandler);\n\t\t});\n\t}\n\n\t// ================================================================\n\t// LocalStorage Persistence\n\t// ================================================================\n\n\tsaveField(pFieldId)\n\t{\n\t\tlet tmpEl = document.getElementById(pFieldId);\n\t\tif (tmpEl)\n\t\t{\n\t\t\tlocalStorage.setItem('dataCloner_' + pFieldId, tmpEl.value);\n\t\t}\n\t}\n\n\trestoreFields()\n\t{\n\t\tlet tmpPersistFields = this.pict.AppData.DataCloner.PersistFields;\n\t\tfor (let i = 0; i < tmpPersistFields.length; i++)\n\t\t{\n\t\t\tlet tmpId = tmpPersistFields[i];\n\t\t\tlet tmpSaved = localStorage.getItem('dataCloner_' + tmpId);\n\t\t\tif (tmpSaved !== null)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(tmpId);\n\t\t\t\tif (tmpEl) tmpEl.value = tmpSaved;\n\t\t\t}\n\t\t}\n\n\t\t// Restore checkbox state\n\t\tlet tmpSyncDeleted = localStorage.getItem('dataCloner_syncDeletedRecords');\n\t\tif (tmpSyncDeleted !== null)\n\t\t{\n\t\t\tdocument.getElementById('syncDeletedRecords').checked = tmpSyncDeleted === 'true';\n\t\t}\n\t\t// Restore sync mode\n\t\tlet tmpSyncMode = localStorage.getItem('dataCloner_syncMode');\n\t\tif (tmpSyncMode === 'Ongoing')\n\t\t{\n\t\t\tdocument.getElementById('syncModeOngoing').checked = true;\n\t\t}\n\t\tlet tmpSolrSecure = localStorage.getItem('dataCloner_solrSecure');\n\t\tif (tmpSolrSecure !== null)\n\t\t{\n\t\t\tdocument.getElementById('solrSecure').checked = tmpSolrSecure === 'true';\n\t\t}\n\t\t// Restore advanced ID pagination checkbox\n\t\tlet tmpAdvancedIDPagination = localStorage.getItem('dataCloner_syncAdvancedIDPagination');\n\t\tif (tmpAdvancedIDPagination !== null)\n\t\t{\n\t\t\tdocument.getElementById('syncAdvancedIDPagination').checked = tmpAdvancedIDPagination === 'true';\n\t\t}\n\t}\n\n\tinitPersistence()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.restoreFields();\n\n\t\tlet tmpPersistFields = this.pict.AppData.DataCloner.PersistFields;\n\t\tfor (let i = 0; i < tmpPersistFields.length; i++)\n\t\t{\n\t\t\t(function(pId)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(pId);\n\t\t\t\tif (tmpEl)\n\t\t\t\t{\n\t\t\t\t\ttmpEl.addEventListener('input', function() { tmpSelf.saveField(pId); });\n\t\t\t\t\ttmpEl.addEventListener('change', function() { tmpSelf.saveField(pId); });\n\t\t\t\t}\n\t\t\t})(tmpPersistFields[i]);\n\t\t}\n\n\t\t// Persist sync deleted checkbox\n\t\tlet tmpSyncDeletedEl = document.getElementById('syncDeletedRecords');\n\t\tif (tmpSyncDeletedEl)\n\t\t{\n\t\t\ttmpSyncDeletedEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncDeletedRecords', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist sync mode radio\n\t\tdocument.querySelectorAll('input[name=\"syncMode\"]').forEach(function(pEl)\n\t\t{\n\t\t\tpEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncMode', this.value);\n\t\t\t});\n\t\t});\n\n\t\t// Persist solr secure checkbox\n\t\tlet tmpSolrSecureEl = document.getElementById('solrSecure');\n\t\tif (tmpSolrSecureEl)\n\t\t{\n\t\t\ttmpSolrSecureEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_solrSecure', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist advanced ID pagination checkbox\n\t\tlet tmpAdvancedIDPaginationEl = document.getElementById('syncAdvancedIDPagination');\n\t\tif (tmpAdvancedIDPaginationEl)\n\t\t{\n\t\t\ttmpAdvancedIDPaginationEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncAdvancedIDPagination', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist auto-process checkboxes\n\t\tlet tmpAutoIds = ['auto1', 'auto2', 'auto3', 'auto4', 'auto5'];\n\t\tfor (let a = 0; a < tmpAutoIds.length; a++)\n\t\t{\n\t\t\t(function(pId)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(pId);\n\t\t\t\tif (tmpEl)\n\t\t\t\t{\n\t\t\t\t\tlet tmpSaved = localStorage.getItem('dataCloner_' + pId);\n\t\t\t\t\tif (tmpSaved !== null) tmpEl.checked = tmpSaved === 'true';\n\t\t\t\t\ttmpEl.addEventListener('change', function()\n\t\t\t\t\t{\n\t\t\t\t\t\tlocalStorage.setItem('dataCloner_' + pId, this.checked);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})(tmpAutoIds[a]);\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Live Status Indicator\n\t// ================================================================\n\n\tstartLiveStatusPolling()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\tif (tmpAppData.LiveStatusTimer) clearInterval(tmpAppData.LiveStatusTimer);\n\t\tthis.pollLiveStatus();\n\t\tlet tmpSelf = this;\n\t\ttmpAppData.LiveStatusTimer = setInterval(function() { tmpSelf.pollLiveStatus(); }, 1500);\n\t}\n\n\tpollLiveStatus()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/live-status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.renderLiveStatus(pData);\n\t\t\t})\n\t\t\t.catch(function()\n\t\t\t{\n\t\t\t\ttmpSelf.renderLiveStatus({ Phase: 'disconnected', Message: 'Cannot reach server', TotalSynced: 0, TotalRecords: 0 });\n\t\t\t});\n\t}\n\n\trenderLiveStatus(pData)\n\t{\n\t\t// Cache the live status data for the detail view\n\t\tthis.pict.AppData.DataCloner.LastLiveStatus = pData;\n\n\t\tlet tmpBar = document.getElementById('liveStatusBar');\n\t\tlet tmpMsg = document.getElementById('liveStatusMessage');\n\t\tlet tmpMeta = document.getElementById('liveStatusMeta');\n\t\tlet tmpProgressFill = document.getElementById('liveStatusProgressFill');\n\t\tif (!tmpBar) return;\n\n\t\t// Update phase class (preserve expanded class if present)\n\t\tlet tmpWasExpanded = tmpBar.classList.contains('expanded');\n\t\ttmpBar.className = 'live-status-bar phase-' + (pData.Phase || 'idle');\n\t\tif (tmpWasExpanded) tmpBar.classList.add('expanded');\n\n\t\t// Update message\n\t\ttmpMsg.textContent = pData.Message || 'Idle';\n\n\t\t// Update meta info\n\t\tlet tmpMetaParts = [];\n\t\tif (pData.Phase === 'syncing' || pData.Phase === 'stopping')\n\t\t{\n\t\t\tif (pData.Elapsed)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + pData.Elapsed + '</span>');\n\t\t\t}\n\t\t\tif (pData.ETA)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">~' + pData.ETA + ' remaining</span>');\n\t\t\t}\n\t\t\tif (pData.TotalTables > 0)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + pData.Completed + '</strong> / ' + pData.TotalTables + ' tables</span>');\n\t\t\t}\n\t\t\tif (pData.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = pData.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\tif (pData.PreCountGrandTotal > 0)\n\t\t\t\t{\n\t\t\t\t\tlet tmpGrandTotal = pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> / ' + tmpGrandTotal + ' records</span>');\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (pData.PreCountGrandTotal > 0)\n\t\t\t{\n\t\t\t\tlet tmpGrandTotal = pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">' + tmpGrandTotal + ' records to sync</span>');\n\t\t\t}\n\t\t\tif (pData.PreCountProgress && pData.PreCountProgress.Counted < pData.PreCountProgress.TotalTables)\n\t\t\t{\n\t\t\t\tlet tmpCountedSoFar = pData.PreCountGrandTotal > 0\n\t\t\t\t\t? ' (' + pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + ' records found)'\n\t\t\t\t\t: '';\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">counting: ' + pData.PreCountProgress.Counted + ' / ' + pData.PreCountProgress.TotalTables + ' tables' + tmpCountedSoFar + '</span>');\n\t\t\t}\n\t\t\tif (pData.Errors > 0)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\" style=\"color:#dc3545\"><strong>' + pData.Errors + '</strong> error' + (pData.Errors === 1 ? '' : 's') + '</span>');\n\t\t\t}\n\t\t}\n\t\telse if (pData.Phase === 'complete')\n\t\t{\n\t\t\tif (pData.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = pData.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records synced</span>');\n\t\t\t}\n\t\t}\n\t\ttmpMeta.innerHTML = tmpMetaParts.join('');\n\n\t\t// Update progress bar\n\t\tlet tmpPct = 0;\n\t\tif (pData.Phase === 'syncing' && pData.PreCountProgress && pData.PreCountProgress.Counted < pData.PreCountProgress.TotalTables)\n\t\t{\n\t\t\t// During counting phase, show table counting progress\n\t\t\ttmpPct = Math.min((pData.PreCountProgress.Counted / pData.PreCountProgress.TotalTables) * 100, 99);\n\t\t}\n\t\telse if (pData.Phase === 'syncing' && pData.PreCountGrandTotal > 0 && pData.TotalSynced > 0)\n\t\t{\n\t\t\ttmpPct = Math.min((pData.TotalSynced / pData.PreCountGrandTotal) * 100, 99.9);\n\t\t}\n\t\telse if (pData.Phase === 'syncing' && pData.TotalTables > 0)\n\t\t{\n\t\t\tlet tmpTablePct = (pData.Completed / pData.TotalTables) * 100;\n\t\t\tif (pData.ActiveProgress && pData.ActiveProgress.Total > 0)\n\t\t\t{\n\t\t\t\tlet tmpEntityPct = (pData.ActiveProgress.Synced / pData.ActiveProgress.Total) * (100 / pData.TotalTables);\n\t\t\t\ttmpPct = tmpTablePct + tmpEntityPct;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpPct = tmpTablePct;\n\t\t\t}\n\t\t}\n\t\telse if (pData.Phase === 'complete')\n\t\t{\n\t\t\ttmpPct = 100;\n\t\t}\n\t\ttmpProgressFill.style.width = Math.min(100, Math.round(tmpPct)) + '%';\n\n\t\t// Auto-expand the detail view when sync starts so users see counting progress\n\t\tif ((pData.Phase === 'syncing' || pData.Phase === 'stopping') && !this.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t{\n\t\t\tlet tmpLayoutView = this.pict.views['DataCloner-Layout'];\n\t\t\tif (tmpLayoutView && typeof tmpLayoutView.toggleStatusDetail === 'function')\n\t\t\t{\n\t\t\t\ttmpLayoutView.toggleStatusDetail();\n\t\t\t}\n\t\t}\n\n\t\t// If the detail view is expanded, re-render it with fresh data\n\t\tif (this.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t{\n\t\t\tthis.renderStatusDetail();\n\t\t}\n\n\t\t// Auto-fetch the sync report when we detect a completed sync but haven't loaded the report yet\n\t\tif (pData.Phase === 'complete' && !this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tlet tmpSelf = this;\n\t\t\tthis.api('GET', '/clone/sync/report')\n\t\t\t\t.then(function(pReportData)\n\t\t\t\t{\n\t\t\t\t\tif (pReportData && pReportData.ReportVersion)\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.LastReport = pReportData;\n\t\t\t\t\t\tif (tmpSelf.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.renderStatusDetail();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch(function() { /* ignore fetch errors */ });\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Status Detail Expansion\n\t// ================================================================\n\n\tonStatusDetailExpanded()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\ttmpAppData.StatusDetailExpanded = true;\n\n\t\t// Immediate render from whatever data we have\n\t\tthis.renderStatusDetail();\n\n\t\t// Start detail polling (poll /sync/status for per-table data)\n\t\tif (tmpAppData.StatusDetailTimer) clearInterval(tmpAppData.StatusDetailTimer);\n\t\tlet tmpSelf = this;\n\t\ttmpAppData.StatusDetailTimer = setInterval(function() { tmpSelf.pollStatusDetail(); }, 2000);\n\t\tthis.pollStatusDetail();\n\t}\n\n\tonStatusDetailCollapsed()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\ttmpAppData.StatusDetailExpanded = false;\n\n\t\tif (tmpAppData.StatusDetailTimer)\n\t\t{\n\t\t\tclearInterval(tmpAppData.StatusDetailTimer);\n\t\t\ttmpAppData.StatusDetailTimer = null;\n\t\t}\n\t}\n\n\tpollStatusDetail()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.AppData.DataCloner.StatusDetailData = pData;\n\t\t\t\ttmpSelf.renderStatusDetail();\n\t\t\t})\n\t\t\t.catch(function() { /* ignore poll errors */ });\n\t}\n\n\trenderCountingPhaseDetail(pContainer, pPreCountProgress)\n\t{\n\t\tlet tmpTables = pPreCountProgress.Tables || [];\n\t\tlet tmpCounted = pPreCountProgress.Counted || 0;\n\t\tlet tmpTotal = pPreCountProgress.TotalTables || 0;\n\t\tlet tmpRunningTotal = 0;\n\n\t\tlet tmpHtml = '<div class=\"status-detail-section\">';\n\t\ttmpHtml += '<div class=\"status-detail-section-title\">Counting Records (' + tmpCounted + ' / ' + tmpTotal + ' tables)</div>';\n\n\t\tif (tmpTables.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<table class=\"precount-table\">';\n\t\t\ttmpHtml += '<thead><tr><th>Table</th><th style=\"text-align:right\">Records</th><th style=\"text-align:right\">Time</th></tr></thead>';\n\t\t\ttmpHtml += '<tbody>';\n\t\t\tfor (let i = 0; i < tmpTables.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpT = tmpTables[i];\n\t\t\t\ttmpRunningTotal += tmpT.Count;\n\t\t\t\tlet tmpCountFmt = this.formatNumber(tmpT.Count);\n\t\t\t\tlet tmpTimeFmt = tmpT.ElapsedMs < 1000\n\t\t\t\t\t? tmpT.ElapsedMs + 'ms'\n\t\t\t\t\t: (tmpT.ElapsedMs / 1000).toFixed(1) + 's';\n\t\t\t\tlet tmpRowClass = tmpT.Error ? ' class=\"precount-error\"' : '';\n\t\t\t\ttmpHtml += '<tr' + tmpRowClass + '>';\n\t\t\t\ttmpHtml += '<td>' + this.escapeHtml(tmpT.Name) + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums\">' + tmpCountFmt + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums; color:#888\">' + tmpTimeFmt + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</tbody>';\n\t\t\ttmpHtml += '<tfoot><tr>';\n\t\t\ttmpHtml += '<td><strong>Total</strong></td>';\n\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums\"><strong>' + this.formatNumber(tmpRunningTotal) + '</strong></td>';\n\t\t\ttmpHtml += '<td></td>';\n\t\t\ttmpHtml += '</tr></tfoot>';\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// Show pending indicator for remaining tables\n\t\tlet tmpRemaining = tmpTotal - tmpCounted;\n\t\tif (tmpRemaining > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"precount-pending\">';\n\t\t\ttmpHtml += '<span class=\"precount-spinner\"></span> ';\n\t\t\ttmpHtml += tmpRemaining + ' table' + (tmpRemaining === 1 ? '' : 's') + ' remaining…';\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\tpContainer.innerHTML = tmpHtml;\n\t}\n\n\trenderStatusDetail()\n\t{\n\t\tlet tmpContainer = document.getElementById('DataCloner-StatusDetail-Container');\n\t\tif (!tmpContainer) return;\n\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\tlet tmpLiveStatus = tmpAppData.LastLiveStatus;\n\t\tlet tmpStatusData = tmpAppData.StatusDetailData;\n\t\tlet tmpReport = tmpAppData.LastReport;\n\n\t\t// During the counting phase, show per-table counts as they arrive\n\t\tif (tmpLiveStatus && tmpLiveStatus.PreCountProgress\n\t\t\t&& tmpLiveStatus.PreCountProgress.Tables\n\t\t\t&& tmpLiveStatus.Phase === 'syncing'\n\t\t\t&& tmpLiveStatus.PreCountProgress.Counted < tmpLiveStatus.PreCountProgress.TotalTables)\n\t\t{\n\t\t\tthis.renderCountingPhaseDetail(tmpContainer, tmpLiveStatus.PreCountProgress);\n\t\t\t// Hide histogram during counting\n\t\t\tlet tmpHistContainer = document.getElementById('DataCloner-Throughput-Histogram');\n\t\t\tif (tmpHistContainer) tmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine data source: live during sync, report after sync\n\t\tlet tmpTables = {};\n\t\tlet tmpThroughputSamples = [];\n\t\tlet tmpEventLog = [];\n\t\tlet tmpIsLive = false;\n\n\t\tif (tmpLiveStatus && (tmpLiveStatus.Phase === 'syncing' || tmpLiveStatus.Phase === 'stopping'))\n\t\t{\n\t\t\ttmpIsLive = true;\n\t\t\tif (tmpStatusData && tmpStatusData.Tables) tmpTables = tmpStatusData.Tables;\n\t\t\tif (tmpLiveStatus.ThroughputSamples) tmpThroughputSamples = tmpLiveStatus.ThroughputSamples;\n\t\t}\n\t\telse if (tmpReport && tmpReport.ReportVersion)\n\t\t{\n\t\t\t// Build tables object from report\n\t\t\tfor (let i = 0; i < tmpReport.Tables.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpT = tmpReport.Tables[i];\n\t\t\t\ttmpTables[tmpT.Name] = tmpT;\n\t\t\t}\n\t\t\ttmpThroughputSamples = tmpReport.ThroughputSamples || [];\n\t\t\ttmpEventLog = tmpReport.EventLog || [];\n\t\t}\n\t\telse if (tmpStatusData && tmpStatusData.Tables)\n\t\t{\n\t\t\ttmpTables = tmpStatusData.Tables;\n\t\t\t// Use throughput samples from live status if available (e.g. after page reload with completed sync)\n\t\t\tif (tmpLiveStatus && tmpLiveStatus.ThroughputSamples)\n\t\t\t{\n\t\t\t\ttmpThroughputSamples = tmpLiveStatus.ThroughputSamples;\n\t\t\t}\n\t\t}\n\n\t\t// Categorize tables\n\t\tlet tmpRunning = [];\n\t\tlet tmpPending = [];\n\t\tlet tmpCompleted = [];\n\t\tlet tmpErrors = [];\n\t\tlet tmpTableNames = Object.keys(tmpTables);\n\n\t\tfor (let i = 0; i < tmpTableNames.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpTableNames[i];\n\t\t\tlet tmpT = tmpTables[tmpName];\n\t\t\tif (tmpT.Status === 'Syncing')\n\t\t\t{\n\t\t\t\ttmpRunning.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Pending')\n\t\t\t{\n\t\t\t\ttmpPending.push(tmpName);\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Complete')\n\t\t\t{\n\t\t\t\ttmpCompleted.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Error' || tmpT.Status === 'Partial')\n\t\t\t{\n\t\t\t\ttmpErrors.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t}\n\n\t\tlet tmpHtml = '';\n\n\t\t// === Section 1: Running Operations ===\n\t\tif (tmpRunning.length > 0 || tmpPending.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Running</div>';\n\t\t\tfor (let i = 0; i < tmpRunning.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpOp = tmpRunning[i];\n\t\t\t\tlet tmpPct = tmpOp.Data.Total > 0 ? Math.round((tmpOp.Data.Synced / tmpOp.Data.Total) * 100) : 0;\n\t\t\t\tlet tmpSyncedFmt = this.formatNumber(tmpOp.Data.Synced || 0);\n\t\t\t\tlet tmpTotalFmt = this.formatNumber(tmpOp.Data.Total || 0);\n\t\t\t\ttmpHtml += '<div class=\"running-op-row\">';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-name\">' + this.escapeHtml(tmpOp.Name) + '</div>';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-bar\"><div class=\"running-op-bar-fill\" style=\"width:' + tmpPct + '%\"></div></div>';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-count\">' + tmpSyncedFmt + ' / ' + tmpTotalFmt + ' (' + tmpPct + '%)</div>';\n\t\t\t\ttmpHtml += '</div>';\n\t\t\t}\n\t\t\tif (tmpPending.length > 0)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"running-op-pending\">' + tmpPending.length + ' table' + (tmpPending.length === 1 ? '' : 's') + ' waiting</div>';\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\t// === Section 2: Completed Successful Operations ===\n\t\tif (tmpCompleted.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Completed (' + tmpCompleted.length + ')</div>';\n\n\t\t\tfor (let i = 0; i < tmpCompleted.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += this.renderCompletedRow(tmpCompleted[i]);\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\t// === Section 3: Unsuccessful Operations ===\n\t\tif (tmpErrors.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Errors (' + tmpErrors.length + ')</div>';\n\t\t\tfor (let i = 0; i < tmpErrors.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += this.renderErrorRow(tmpErrors[i], tmpEventLog);\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\tif (tmpHtml === '')\n\t\t{\n\t\t\tif (tmpIsLive)\n\t\t\t{\n\t\t\t\ttmpHtml = '<div style=\"font-size:0.9em; color:#888; padding:8px 0\">Sync in progress, waiting for table data\\u2026</div>';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpHtml = '<div style=\"font-size:0.9em; color:#888; padding:8px 0\">No sync data available. Run a sync to see operation details here.</div>';\n\t\t\t}\n\t\t}\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\n\t\t// Update the throughput histogram via pict-section-histogram\n\t\tthis.updateThroughputHistogram(tmpThroughputSamples);\n\t}\n\n\tupdateThroughputHistogram(pSamples)\n\t{\n\t\tlet tmpHistContainer = document.getElementById('DataCloner-Throughput-Histogram');\n\t\tif (!tmpHistContainer) return;\n\n\t\tif (!pSamples || pSamples.length < 2)\n\t\t{\n\t\t\ttmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// --- Step 1: Compute raw deltas per 10s interval ---\n\t\tlet tmpRawDeltas = [];\n\t\tfor (let i = 1; i < pSamples.length; i++)\n\t\t{\n\t\t\tlet tmpDelta = pSamples[i].synced - pSamples[i - 1].synced;\n\t\t\tif (tmpDelta < 0) tmpDelta = 0;\n\t\t\ttmpRawDeltas.push({ delta: tmpDelta, t: pSamples[i].t });\n\t\t}\n\n\t\t// --- Step 2: Downsample if there are too many bars ---\n\t\tlet tmpContainerWidth = tmpHistContainer.clientWidth || 800;\n\t\tlet tmpMaxBars = Math.max(20, Math.floor(tmpContainerWidth / 6));\n\t\tlet tmpAggregated = tmpRawDeltas;\n\n\t\tif (tmpRawDeltas.length > tmpMaxBars)\n\t\t{\n\t\t\tlet tmpBucketSize = Math.ceil(tmpRawDeltas.length / tmpMaxBars);\n\t\t\ttmpAggregated = [];\n\t\t\tfor (let i = 0; i < tmpRawDeltas.length; i += tmpBucketSize)\n\t\t\t{\n\t\t\t\tlet tmpSum = 0;\n\t\t\t\tlet tmpLastT = 0;\n\t\t\t\tfor (let j = i; j < Math.min(i + tmpBucketSize, tmpRawDeltas.length); j++)\n\t\t\t\t{\n\t\t\t\t\ttmpSum += tmpRawDeltas[j].delta;\n\t\t\t\t\ttmpLastT = tmpRawDeltas[j].t;\n\t\t\t\t}\n\t\t\t\ttmpAggregated.push({ delta: tmpSum, t: tmpLastT });\n\t\t\t}\n\t\t}\n\n\t\t// --- Step 3: Check for data ---\n\t\tlet tmpHasData = false;\n\t\tfor (let i = 0; i < tmpAggregated.length; i++)\n\t\t{\n\t\t\tif (tmpAggregated[i].delta > 0) { tmpHasData = true; break; }\n\t\t}\n\t\tif (!tmpHasData)\n\t\t{\n\t\t\ttmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// --- Step 4: Build bins for the histogram library ---\n\t\tlet tmpStartT = pSamples[0].t;\n\t\tlet tmpBins = [];\n\t\tfor (let i = 0; i < tmpAggregated.length; i++)\n\t\t{\n\t\t\tlet tmpElapsedSec = Math.round((tmpAggregated[i].t - tmpStartT) / 1000);\n\t\t\ttmpBins.push({\n\t\t\t\tLabel: this.formatElapsed(tmpElapsedSec),\n\t\t\t\tValue: tmpAggregated[i].delta\n\t\t\t});\n\t\t}\n\n\t\t// --- Step 5: Update the histogram view via the library ---\n\t\ttmpHistContainer.style.display = '';\n\t\tlet tmpHistView = this.pict.views['DataCloner-StatusHistogram'];\n\t\tif (tmpHistView)\n\t\t{\n\t\t\ttmpHistView.setBins(tmpBins);\n\t\t\ttmpHistView.renderHistogram();\n\t\t}\n\t}\n\n\tformatElapsed(pSec)\n\t{\n\t\tif (pSec < 60) return pSec + 's';\n\t\tif (pSec < 3600)\n\t\t{\n\t\t\tlet tmpM = Math.floor(pSec / 60);\n\t\t\tlet tmpS = pSec % 60;\n\t\t\treturn tmpM + ':' + (tmpS < 10 ? '0' : '') + tmpS;\n\t\t}\n\t\tlet tmpH = Math.floor(pSec / 3600);\n\t\tlet tmpM = Math.floor((pSec % 3600) / 60);\n\t\treturn tmpH + 'h' + (tmpM < 10 ? '0' : '') + tmpM;\n\t}\n\n\tformatCompact(pNum)\n\t{\n\t\tif (pNum >= 1000000) return (pNum / 1000000).toFixed(1) + 'M';\n\t\tif (pNum >= 10000) return (pNum / 1000).toFixed(0) + 'K';\n\t\tif (pNum >= 1000) return (pNum / 1000).toFixed(1) + 'K';\n\t\treturn pNum.toString();\n\t}\n\n\tformatNumber(pNum)\n\t{\n\t\treturn pNum.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t}\n\n\trenderCompletedRow(pOp)\n\t{\n\t\tlet tmpNew = pOp.Data.New || 0;\n\t\tlet tmpUpdated = pOp.Data.Updated || 0;\n\t\tlet tmpUnchanged = pOp.Data.Unchanged || 0;\n\t\tlet tmpDeleted = pOp.Data.Deleted || 0;\n\t\tlet tmpServerTotal = pOp.Data.ServerTotal || 0;\n\n\t\t// Grand total for the ratio bar: all records the adapter dealt with\n\t\tlet tmpGrandTotal = tmpUnchanged + tmpNew + tmpUpdated + tmpDeleted;\n\t\tif (tmpGrandTotal === 0 && tmpServerTotal > 0)\n\t\t{\n\t\t\ttmpGrandTotal = tmpServerTotal;\n\t\t\ttmpUnchanged = tmpServerTotal;\n\t\t}\n\n\t\tlet tmpHtml = '<div class=\"completed-op-row\">';\n\t\ttmpHtml += '<div class=\"completed-op-header\">';\n\t\ttmpHtml += ' <span class=\"completed-op-checkmark\">\\u2713</span>';\n\t\ttmpHtml += ' <span class=\"completed-op-name\">' + this.escapeHtml(pOp.Name) + '</span>';\n\t\ttmpHtml += '</div>';\n\n\t\t// Ratio bar: Unchanged / New / Updated / Deleted\n\t\tif (tmpGrandTotal > 0)\n\t\t{\n\t\t\tlet tmpUnchangedPct = Math.round((tmpUnchanged / tmpGrandTotal) * 100);\n\t\t\tlet tmpNewPct = Math.round((tmpNew / tmpGrandTotal) * 100);\n\t\t\tlet tmpUpdatedPct = Math.round((tmpUpdated / tmpGrandTotal) * 100);\n\t\t\tlet tmpDeletedPct = Math.round((tmpDeleted / tmpGrandTotal) * 100);\n\n\t\t\t// Ensure percentages sum to 100\n\t\t\tlet tmpPctSum = tmpUnchangedPct + tmpNewPct + tmpUpdatedPct + tmpDeletedPct;\n\t\t\tif (tmpPctSum !== 100 && tmpPctSum > 0)\n\t\t\t{\n\t\t\t\ttmpUnchangedPct += (100 - tmpPctSum);\n\t\t\t\tif (tmpUnchangedPct < 0) tmpUnchangedPct = 0;\n\t\t\t}\n\n\t\t\ttmpHtml += '<div class=\"ratio-bar-container\">';\n\t\t\tif (tmpUnchangedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment unchanged\" style=\"width:' + tmpUnchangedPct + '%\" title=\"Unchanged: ' + this.formatNumber(tmpUnchanged) + '\"></div>';\n\t\t\tif (tmpNewPct > 0) tmpHtml += '<div class=\"ratio-bar-segment new-records\" style=\"width:' + tmpNewPct + '%\" title=\"New: ' + this.formatNumber(tmpNew) + '\"></div>';\n\t\t\tif (tmpUpdatedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment updated\" style=\"width:' + tmpUpdatedPct + '%\" title=\"Updated: ' + this.formatNumber(tmpUpdated) + '\"></div>';\n\t\t\tif (tmpDeletedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment deleted\" style=\"width:' + tmpDeletedPct + '%\" title=\"Deleted: ' + this.formatNumber(tmpDeleted) + '\"></div>';\n\t\t\ttmpHtml += '</div>';\n\n\t\t\ttmpHtml += '<div class=\"ratio-bar-legend\">';\n\t\t\tif (tmpUnchanged > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot unchanged-dot\"></span> Unchanged (' + this.formatNumber(tmpUnchanged) + ')</span>';\n\t\t\tif (tmpNew > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot new-dot\"></span> New (' + this.formatNumber(tmpNew) + ')</span>';\n\t\t\tif (tmpUpdated > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot updated-dot\"></span> Updated (' + this.formatNumber(tmpUpdated) + ')</span>';\n\t\t\tif (tmpDeleted > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot deleted-dot\"></span> Deleted (' + this.formatNumber(tmpDeleted) + ')</span>';\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\trenderErrorRow(pOp, pEventLog)\n\t{\n\t\tlet tmpSynced = pOp.Data.Synced || 0;\n\t\tlet tmpTotal = pOp.Data.Total || 0;\n\t\tlet tmpSyncedFmt = this.formatNumber(tmpSynced);\n\t\tlet tmpTotalFmt = this.formatNumber(tmpTotal);\n\n\t\tlet tmpHtml = '<div class=\"error-op-row\">';\n\t\ttmpHtml += '<div class=\"error-op-header\">';\n\t\ttmpHtml += ' <span style=\"color:#dc3545\">\\u2717</span>';\n\t\ttmpHtml += ' <span class=\"error-op-name\">' + this.escapeHtml(pOp.Name) + '</span>';\n\t\ttmpHtml += ' <span class=\"error-op-status\">' + pOp.Data.Status + ' \\u2014 ' + tmpSyncedFmt + ' / ' + tmpTotalFmt + '</span>';\n\t\ttmpHtml += '</div>';\n\n\t\tif (pOp.Data.ErrorMessage)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"error-op-message\">' + this.escapeHtml(pOp.Data.ErrorMessage) + '</div>';\n\t\t}\n\n\t\t// Extract relevant log entries from EventLog\n\t\tif (pEventLog && pEventLog.length > 0)\n\t\t{\n\t\t\tlet tmpRelevantLogs = [];\n\t\t\tfor (let j = 0; j < pEventLog.length; j++)\n\t\t\t{\n\t\t\t\tlet tmpLog = pEventLog[j];\n\t\t\t\tif (tmpLog.Data && tmpLog.Data.Table === pOp.Name &&\n\t\t\t\t\t(tmpLog.Type === 'TableError' || tmpLog.Type === 'TablePartial'))\n\t\t\t\t{\n\t\t\t\t\ttmpRelevantLogs.push(tmpLog);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tmpRelevantLogs.length > 0)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"error-op-log-entries\">';\n\t\t\t\tfor (let j = 0; j < tmpRelevantLogs.length; j++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpTimestamp = tmpRelevantLogs[j].Timestamp.replace('T', ' ').replace(/\\.\\d+Z$/, '');\n\t\t\t\t\ttmpHtml += '<div>' + this.escapeHtml(tmpTimestamp + ' ' + tmpRelevantLogs[j].Message) + '</div>';\n\t\t\t\t}\n\t\t\t\ttmpHtml += '</div>';\n\t\t\t}\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\t// ================================================================\n\t// Deployed Tables Persistence\n\t// ================================================================\n\n\tsaveDeployedTables()\n\t{\n\t\tlocalStorage.setItem('dataCloner_deployedTables', JSON.stringify(this.pict.AppData.DataCloner.DeployedTables));\n\t}\n\n\trestoreDeployedTables()\n\t{\n\t\ttry\n\t\t{\n\t\t\tlet tmpRaw = localStorage.getItem('dataCloner_deployedTables');\n\t\t\tif (tmpRaw)\n\t\t\t{\n\t\t\t\tthis.pict.AppData.DataCloner.DeployedTables = JSON.parse(tmpRaw);\n\t\t\t\tthis.pict.views['DataCloner-ViewData'].populateViewTableDropdown();\n\t\t\t}\n\t\t}\n\t\tcatch (pError) { /* ignore */ }\n\t}\n\n\t// ================================================================\n\t// Auto-Process\n\t// ================================================================\n\n\tinitAutoProcess()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/live-status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Phase === 'syncing' || pData.Phase === 'stopping')\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.ServerBusyAtLoad = true;\n\t\t\t\t\ttmpSelf.setSectionPhase(5, 'busy');\n\t\t\t\t\ttmpSelf.pict.views['DataCloner-Sync'].startPolling();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttmpSelf.runAutoProcessChain();\n\t\t\t})\n\t\t\t.catch(function()\n\t\t\t{\n\t\t\t\t// Server unreachable — don't auto-process\n\t\t\t});\n\t}\n\n\trunAutoProcessChain()\n\t{\n\t\tlet tmpSelf = this;\n\t\tlet tmpDelay = 0;\n\t\tlet tmpStepDelay = 2000;\n\n\t\tif (document.getElementById('auto1') && document.getElementById('auto1').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Connection'].connectProvider(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto2') && document.getElementById('auto2').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Session'].goAction(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay + 1500;\n\t\t}\n\t\tif (document.getElementById('auto3') && document.getElementById('auto3').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Schema'].fetchSchema(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto4') && document.getElementById('auto4').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Deploy'].deploySchema(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto5') && document.getElementById('auto5').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Sync'].startSync(); }, tmpDelay);\n\t\t}\n\t}\n}\n\nmodule.exports = DataClonerProvider;\n\nmodule.exports.default_configuration =\n{\n\tProviderIdentifier: 'DataCloner',\n\tAutoInitialize: true,\n\tAutoInitializeOrdinal: 0\n};\n\n},{\"pict-provider\":6}],19:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerConnectionView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tonProviderChange()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpProviders = ['SQLite', 'MySQL', 'MSSQL', 'PostgreSQL', 'Solr', 'MongoDB', 'RocksDB', 'Bibliograph'];\n\t\tfor (let i = 0; i < tmpProviders.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById('config' + tmpProviders[i]);\n\t\t\tif (tmpEl)\n\t\t\t{\n\t\t\t\ttmpEl.style.display = (tmpProvider === tmpProviders[i]) ? '' : 'none';\n\t\t\t}\n\t\t}\n\t\tthis.pict.providers.DataCloner.saveField('connProvider');\n\t}\n\n\tgetProviderConfig()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\ttmpConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || 'data/cloned.sqlite';\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpConfig.password = document.getElementById('mysqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mysqlDatabase').value.trim();\n\t\t\ttmpConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpConfig.password = document.getElementById('mssqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mssqlDatabase').value.trim();\n\t\t\ttmpConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;\n\t\t\ttmpConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';\n\t\t\ttmpConfig.password = document.getElementById('postgresqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('postgresqlDatabase').value.trim();\n\t\t\ttmpConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;\n\t\t}\n\t\telse if (tmpProvider === 'Solr')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('solrHost').value.trim() || 'localhost';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('solrPort').value, 10) || 8983;\n\t\t\ttmpConfig.core = document.getElementById('solrCore').value.trim() || 'default';\n\t\t\ttmpConfig.path = document.getElementById('solrPath').value.trim() || '/solr';\n\t\t\ttmpConfig.secure = document.getElementById('solrSecure').checked;\n\t\t}\n\t\telse if (tmpProvider === 'MongoDB')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('mongodbHost').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mongodbPort').value, 10) || 27017;\n\t\t\ttmpConfig.user = document.getElementById('mongodbUser').value.trim();\n\t\t\ttmpConfig.password = document.getElementById('mongodbPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mongodbDatabase').value.trim() || 'test';\n\t\t\ttmpConfig.maxPoolSize = parseInt(document.getElementById('mongodbConnectionLimit').value, 10) || 10;\n\t\t}\n\t\telse if (tmpProvider === 'RocksDB')\n\t\t{\n\t\t\ttmpConfig.RocksDBFolder = document.getElementById('rocksdbFolder').value.trim() || 'data/rocksdb';\n\t\t}\n\t\telse if (tmpProvider === 'Bibliograph')\n\t\t{\n\t\t\ttmpConfig.StorageFolder = document.getElementById('bibliographFolder').value.trim() || 'data/bibliograph';\n\t\t}\n\n\t\treturn { Provider: tmpProvider, Config: tmpConfig };\n\t}\n\n\tconnectProvider()\n\t{\n\t\tlet tmpConnInfo = this.getProviderConfig();\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connecting to ' + tmpConnInfo.Provider + '...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/connection/configure', tmpConnInfo)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connection failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'error');\n\t\t\t\t});\n\t}\n\n\ttestConnection()\n\t{\n\t\tlet tmpConnInfo = this.getProviderConfig();\n\n\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Testing ' + tmpConnInfo.Provider + ' connection...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/connection/test', tmpConnInfo)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Test failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tcheckConnectionStatus()\n\t{\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/connection/status')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Connected)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connected: ' + pData.Provider, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'ok');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t() =>\n\t\t\t\t{\n\t\t\t\t\t/* ignore */\n\t\t\t\t});\n\t}\n}\n\nmodule.exports = DataClonerConnectionView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Connection',\n\tDefaultRenderable: 'DataCloner-Connection',\n\tDefaultDestinationAddress: '#DataCloner-Section-Connection',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Connection',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">1</div>\n\t<div class=\"accordion-card\" id=\"section1\" data-section=\"1\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section1')\">\n\t\t\t<div class=\"accordion-title\">Database Connection</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase1\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview1\">SQLite at data/cloned.sqlite</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Connection'].connectProvider()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto1\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Configure the local database where cloned data will be stored. SQLite is connected by default.</p>\n\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:0 0 200px\">\n\t\t\t\t\t<label for=\"connProvider\">Provider</label>\n\t\t\t\t\t<select id=\"connProvider\" onchange=\"pict.views['DataCloner-Connection'].onProviderChange()\">\n\t\t\t\t\t\t<option value=\"SQLite\" selected>SQLite</option>\n\t\t\t\t\t\t<option value=\"MySQL\">MySQL</option>\n\t\t\t\t\t\t<option value=\"MSSQL\">MSSQL</option>\n\t\t\t\t\t\t<option value=\"PostgreSQL\">PostgreSQL</option>\n\t\t\t\t\t\t<option value=\"Solr\">Solr</option>\n\t\t\t\t\t\t<option value=\"MongoDB\">MongoDB</option>\n\t\t\t\t\t\t<option value=\"RocksDB\">RocksDB</option>\n\t\t\t\t\t\t<option value=\"Bibliograph\">Bibliograph</option>\n\t\t\t\t\t</select>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:1; display:flex; align-items:flex-end; gap:8px\">\n\t\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Connection'].connectProvider()\">Connect</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Connection'].testConnection()\">Test Connection</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- SQLite Config -->\n\t\t\t<div id=\"configSQLite\">\n\t\t\t\t<label for=\"sqliteFilePath\">SQLite File Path</label>\n\t\t\t\t<input type=\"text\" id=\"sqliteFilePath\" placeholder=\"data/cloned.sqlite\" value=\"data/cloned.sqlite\">\n\t\t\t</div>\n\n\t\t\t<!-- MySQL Config -->\n\t\t\t<div id=\"configMySQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mysqlServer\">Server</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mysqlServer\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mysqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mysqlPort\" placeholder=\"3306\" value=\"3306\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mysqlUser\" placeholder=\"root\" value=\"root\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mysqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mysqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mysqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlConnectionLimit\">Connection Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mysqlConnectionLimit\" placeholder=\"20\" value=\"20\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- MSSQL Config -->\n\t\t\t<div id=\"configMSSQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mssqlServer\">Server</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mssqlServer\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mssqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mssqlPort\" placeholder=\"1433\" value=\"1433\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mssqlUser\" placeholder=\"sa\" value=\"sa\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mssqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mssqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mssqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlConnectionLimit\">Connection Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mssqlConnectionLimit\" placeholder=\"20\" value=\"20\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- PostgreSQL Config -->\n\t\t\t<div id=\"configPostgreSQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"postgresqlHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"postgresqlHost\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"postgresqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"postgresqlPort\" placeholder=\"5432\" value=\"5432\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"postgresqlUser\" placeholder=\"postgres\" value=\"postgres\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"postgresqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"postgresqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"postgresqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlConnectionLimit\">Connection Pool Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"postgresqlConnectionLimit\" placeholder=\"10\" value=\"10\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- Solr Config -->\n\t\t\t<div id=\"configSolr\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"solrHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrHost\" placeholder=\"localhost\" value=\"localhost\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"solrPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"solrPort\" placeholder=\"8983\" value=\"8983\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"solrCore\">Core</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrCore\" placeholder=\"default\" value=\"default\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"solrPath\">Path</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrPath\" placeholder=\"/solr\" value=\"/solr\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t\t<input type=\"checkbox\" id=\"solrSecure\">\n\t\t\t\t\t<label for=\"solrSecure\">Use HTTPS</label>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- MongoDB Config -->\n\t\t\t<div id=\"configMongoDB\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mongodbHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mongodbHost\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mongodbPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mongodbPort\" placeholder=\"27017\" value=\"27017\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mongodbUser\" placeholder=\"(optional)\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mongodbPassword\" placeholder=\"(optional)\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mongodbDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mongodbDatabase\" placeholder=\"test\" value=\"test\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbConnectionLimit\">Max Pool Size</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mongodbConnectionLimit\" placeholder=\"10\" value=\"10\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- RocksDB Config -->\n\t\t\t<div id=\"configRocksDB\" style=\"display:none\">\n\t\t\t\t<label for=\"rocksdbFolder\">RocksDB Folder Path</label>\n\t\t\t\t<input type=\"text\" id=\"rocksdbFolder\" placeholder=\"data/rocksdb\" value=\"data/rocksdb\">\n\t\t\t</div>\n\n\t\t\t<!-- Bibliograph Config -->\n\t\t\t<div id=\"configBibliograph\" style=\"display:none\">\n\t\t\t\t<label for=\"bibliographFolder\">Storage Folder Path</label>\n\t\t\t\t<input type=\"text\" id=\"bibliographFolder\" placeholder=\"data/bibliograph\" value=\"data/bibliograph\">\n\t\t\t</div>\n\n\t\t\t<div id=\"connectionStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Connection',\n\t\t\tTemplateHash: 'DataCloner-Connection',\n\t\t\tDestinationAddress: '#DataCloner-Section-Connection'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],20:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerDeployView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tdeploySchema()\n\t{\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\n\t\tif (tmpSelectedTables.length === 0)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'No tables selected. Fetch a schema and select tables first.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(4, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'Deploying ' + tmpSelectedTables.length + ' tables...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/deploy', { Tables: tmpSelectedTables })\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', pData.Message, 'ok');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'ok');\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.DeployedTables = pData.TablesDeployed || tmpSelectedTables;\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.saveDeployedTables();\n\t\t\t\t\ttmpSelf.pict.views['DataCloner-ViewData'].populateViewTableDropdown();\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.updateAllPreviews();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Deploy failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\t});\n\t}\n\n\tresetDatabase()\n\t{\n\t\tif (!confirm('This will delete ALL data in the local SQLite database. Continue?'))\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'Resetting database...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/reset')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', pData.Message, 'ok');\n\t\t\t\t\t// Clear the sync progress display\n\t\t\t\t\tlet tmpSyncProgress = document.getElementById('syncProgress');\n\t\t\t\t\tif (tmpSyncProgress) tmpSyncProgress.innerHTML = '';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Reset failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n}\n\nmodule.exports = DataClonerDeployView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Deploy',\n\tDefaultRenderable: 'DataCloner-Deploy',\n\tDefaultDestinationAddress: '#DataCloner-Section-Deploy',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Deploy',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">4</div>\n\t<div class=\"accordion-card\" id=\"section4\" data-section=\"4\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section4')\">\n\t\t\t<div class=\"accordion-title\">Deploy Schema</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase4\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview4\">Create selected tables in the local database</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Deploy'].deploySchema()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto4\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Creates the selected tables in the local database and sets up CRUD endpoints (e.g. GET /1.0/Documents).</p>\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Deploy'].deploySchema()\">Deploy Selected Tables</button>\n\t\t\t<button class=\"danger\" onclick=\"pict.views['DataCloner-Deploy'].resetDatabase()\">Reset Database</button>\n\t\t\t<div id=\"deployStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Deploy',\n\t\t\tTemplateHash: 'DataCloner-Deploy',\n\t\t\tDestinationAddress: '#DataCloner-Section-Deploy'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],21:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerExportView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tbuildConfigObject()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\t// ---- Local Database ----\n\t\ttmpConfig.LocalDatabase = { Provider: tmpProvider, Config: {} };\n\t\tlet tmpDbConfig = tmpConfig.LocalDatabase.Config;\n\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\ttmpDbConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || 'data/cloned.sqlite';\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpDbConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpDbConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpDbConfig.password = document.getElementById('mysqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('mysqlDatabase').value.trim();\n\t\t\ttmpDbConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpDbConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpDbConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpDbConfig.password = document.getElementById('mssqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('mssqlDatabase').value.trim();\n\t\t\ttmpDbConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\ttmpDbConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;\n\t\t\ttmpDbConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';\n\t\t\ttmpDbConfig.password = document.getElementById('postgresqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('postgresqlDatabase').value.trim();\n\t\t\ttmpDbConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;\n\t\t}\n\n\t\t// ---- Remote Session ----\n\t\ttmpConfig.RemoteSession = {};\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\tif (tmpServerURL) tmpConfig.RemoteSession.ServerURL = tmpServerURL + '/1.0/';\n\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim();\n\t\tif (tmpAuthMethod) tmpConfig.RemoteSession.AuthenticationMethod = tmpAuthMethod;\n\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI) tmpConfig.RemoteSession.AuthenticationURITemplate = tmpAuthURI;\n\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI) tmpConfig.RemoteSession.CheckSessionURITemplate = tmpCheckURI;\n\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\tif (tmpCookieName) tmpConfig.RemoteSession.CookieName = tmpCookieName;\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr) tmpConfig.RemoteSession.CookieValueAddress = tmpCookieValueAddr;\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate) tmpConfig.RemoteSession.CookieValueTemplate = tmpCookieValueTemplate;\n\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\tif (tmpLoginMarker) tmpConfig.RemoteSession.CheckSessionLoginMarker = tmpLoginMarker;\n\n\t\t// ---- Credentials ----\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value;\n\t\tif (tmpUserName || tmpPassword)\n\t\t{\n\t\t\ttmpConfig.Credentials = {};\n\t\t\tif (tmpUserName) tmpConfig.Credentials.UserName = tmpUserName;\n\t\t\tif (tmpPassword) tmpConfig.Credentials.Password = tmpPassword;\n\t\t}\n\n\t\t// ---- Schema ----\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tif (tmpSchemaURL) tmpConfig.SchemaURL = tmpSchemaURL;\n\n\t\t// ---- Tables ----\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\tif (tmpSelectedTables.length > 0) tmpConfig.Tables = tmpSelectedTables;\n\n\t\t// ---- Sync Options ----\n\t\ttmpConfig.Sync = {};\n\t\ttmpConfig.Sync.Mode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\ttmpConfig.Sync.PageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\ttmpConfig.Sync.SyncDeletedRecords = document.getElementById('syncDeletedRecords').checked;\n\t\tlet tmpPrecision = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (!isNaN(tmpPrecision) && tmpPrecision !== 1000) tmpConfig.Sync.DateTimePrecisionMS = tmpPrecision;\n\t\tlet tmpMaxRecords = parseInt(document.getElementById('syncMaxRecords').value, 10);\n\t\tif (tmpMaxRecords > 0) tmpConfig.Sync.MaxRecords = tmpMaxRecords;\n\t\tif (document.getElementById('syncAdvancedIDPagination').checked) tmpConfig.Sync.UseAdvancedIDPagination = true;\n\n\t\treturn tmpConfig;\n\t}\n\n\tbuildMeadowIntegrationConfig()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\t// ---- Source ----\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\ttmpConfig.Source = { ServerURL: tmpServerURL ? tmpServerURL + '/1.0/' : 'https://localhost:8080/1.0/' };\n\t\t// When SessionManager handles auth, Source credentials are not needed\n\t\ttmpConfig.Source.UserID = false;\n\t\ttmpConfig.Source.Password = false;\n\n\t\t// ---- Destination ----\n\t\t// meadow-integration clone supports MySQL and MSSQL\n\t\ttmpConfig.Destination = {};\n\t\tif (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpConfig.Destination.Provider = 'MySQL';\n\t\t\ttmpConfig.Destination.MySQL = {};\n\t\t\ttmpConfig.Destination.MySQL.server = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.Destination.MySQL.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpConfig.Destination.MySQL.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpConfig.Destination.MySQL.password = document.getElementById('mysqlPassword').value || '';\n\t\t\ttmpConfig.Destination.MySQL.database = document.getElementById('mysqlDatabase').value.trim() || 'meadow';\n\t\t\ttmpConfig.Destination.MySQL.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpConfig.Destination.Provider = 'MSSQL';\n\t\t\ttmpConfig.Destination.MSSQL = {};\n\t\t\ttmpConfig.Destination.MSSQL.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.Destination.MSSQL.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpConfig.Destination.MSSQL.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpConfig.Destination.MSSQL.password = document.getElementById('mssqlPassword').value || '';\n\t\t\ttmpConfig.Destination.MSSQL.database = document.getElementById('mssqlDatabase').value.trim() || 'meadow';\n\t\t\ttmpConfig.Destination.MSSQL.ConnectionPoolLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Default to MySQL placeholder for unsupported providers\n\t\t\ttmpConfig.Destination.Provider = 'MySQL';\n\t\t\ttmpConfig.Destination.MySQL = { server: '127.0.0.1', port: 3306, user: 'root', password: '', database: 'meadow', connectionLimit: 20 };\n\t\t}\n\n\t\t// ---- Schema ----\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tif (tmpSchemaURL)\n\t\t{\n\t\t\ttmpConfig.SchemaURL = tmpSchemaURL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpConfig.SchemaPath = './schema/Model-Extended.json';\n\t\t}\n\n\t\t// ---- Sync ----\n\t\ttmpConfig.Sync = {};\n\t\ttmpConfig.Sync.DefaultSyncMode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\ttmpConfig.Sync.PageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\tlet tmpMdwintPrecision = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (!isNaN(tmpMdwintPrecision)) tmpConfig.Sync.DateTimePrecisionMS = tmpMdwintPrecision;\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\ttmpConfig.Sync.SyncEntityList = tmpSelectedTables.length > 0 ? tmpSelectedTables : [];\n\t\ttmpConfig.Sync.SyncEntityOptions = {};\n\t\tif (document.getElementById('syncAdvancedIDPagination').checked) tmpConfig.Sync.UseAdvancedIDPagination = true;\n\n\t\t// ---- SessionManager ----\n\t\ttmpConfig.SessionManager = { Sessions: {} };\n\n\t\tlet tmpSessionConfig = {};\n\t\ttmpSessionConfig.Type = 'Cookie';\n\n\t\t// Authentication method\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim() || 'get';\n\t\ttmpSessionConfig.AuthenticationMethod = tmpAuthMethod;\n\n\t\t// Build the authentication URI template\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI)\n\t\t{\n\t\t\t// If the URI is a relative path, prepend the server URL\n\t\t\tif (tmpAuthURI.charAt(0) === '/')\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = (tmpServerURL || '') + tmpAuthURI;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpAuthURI;\n\t\t\t}\n\t\t}\n\t\telse if (tmpServerURL)\n\t\t{\n\t\t\t// Default: Meadow-style GET authentication\n\t\t\tif (tmpAuthMethod === 'post')\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpServerURL + '/1.0/Authenticate';\n\t\t\t\ttmpSessionConfig.AuthenticationRequestBody = {\n\t\t\t\t\tUserName: '{~D:Record.UserName~}',\n\t\t\t\t\tPassword: '{~D:Record.Password~}'\n\t\t\t\t};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpServerURL + '/1.0/Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}';\n\t\t\t}\n\t\t}\n\n\t\t// Check session URI\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI)\n\t\t{\n\t\t\ttmpSessionConfig.CheckSessionURITemplate = tmpCheckURI.charAt(0) === '/' ? (tmpServerURL || '') + tmpCheckURI : tmpCheckURI;\n\t\t}\n\t\telse if (tmpServerURL)\n\t\t{\n\t\t\ttmpSessionConfig.CheckSessionURITemplate = tmpServerURL + '/1.0/CheckSession';\n\t\t}\n\n\t\t// Login marker\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\ttmpSessionConfig.CheckSessionLoginMarkerType = 'boolean';\n\t\ttmpSessionConfig.CheckSessionLoginMarker = tmpLoginMarker || 'LoggedIn';\n\n\t\t// Domain match — extract from server URL for auto-injection\n\t\tif (tmpServerURL)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tlet tmpUrlObj = new URL(tmpServerURL);\n\t\t\t\ttmpSessionConfig.DomainMatch = tmpUrlObj.host;\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\ttmpSessionConfig.DomainMatch = tmpServerURL;\n\t\t\t}\n\t\t}\n\n\t\t// Cookie injection\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\ttmpSessionConfig.CookieName = tmpCookieName || 'SessionID';\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr) tmpSessionConfig.CookieValueAddress = tmpCookieValueAddr;\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate) tmpSessionConfig.CookieValueTemplate = tmpCookieValueTemplate;\n\n\t\t// Credentials\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value;\n\t\ttmpSessionConfig.Credentials = {};\n\t\tif (tmpUserName) tmpSessionConfig.Credentials.UserName = tmpUserName;\n\t\tif (tmpPassword) tmpSessionConfig.Credentials.Password = tmpPassword;\n\n\t\ttmpConfig.SessionManager.Sessions.SourceAPI = tmpSessionConfig;\n\n\t\treturn tmpConfig;\n\t}\n\n\tgenerateConfig()\n\t{\n\t\tlet tmpConfig = this.buildConfigObject();\n\t\tlet tmpJson = JSON.stringify(tmpConfig, null, '\\t');\n\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\ttmpTextarea.value = tmpJson;\n\t\ttmpTextarea.style.display = '';\n\n\t\t// Build CLI flags from export options\n\t\tlet tmpLogFlag = document.getElementById('syncLogFile').checked ? ' --log' : '';\n\t\tlet tmpMaxFlag = '';\n\t\tlet tmpExportMax = parseInt(document.getElementById('syncMaxRecords').value, 10);\n\t\tif (tmpExportMax > 0) tmpMaxFlag = ' --max ' + tmpExportMax;\n\n\t\t// Build CLI command (with config file)\n\t\tlet tmpCliDiv = document.getElementById('cliCommand');\n\t\ttmpCliDiv.style.display = '';\n\t\ttmpCliDiv.querySelector('div').textContent = 'npx retold-data-service-clone --config clone-config.json --run' + tmpLogFlag + tmpMaxFlag;\n\n\t\t// Build one-liner (no config file needed) using --config-json\n\t\tlet tmpOneShotDiv = document.getElementById('cliOneShot');\n\t\ttmpOneShotDiv.style.display = '';\n\t\tlet tmpCompactJSON = JSON.stringify(tmpConfig);\n\t\t// Escape single quotes for shell wrapping\n\t\tlet tmpEscapedJSON = tmpCompactJSON.replace(/'/g, \"'\\\\''\");\n\t\tlet tmpOneShot = \"npx retold-data-service-clone --config-json '\" + tmpEscapedJSON + \"' --run\" + tmpLogFlag + tmpMaxFlag;\n\t\ttmpOneShotDiv.querySelector('div').textContent = tmpOneShot;\n\n\t\t// ---- meadow-integration (mdwint clone) config ----\n\t\tlet tmpMdwintConfig = this.buildMeadowIntegrationConfig();\n\t\tlet tmpMdwintJSON = JSON.stringify(tmpMdwintConfig, null, '\\t');\n\n\t\tlet tmpMdwintDiv = document.getElementById('mdwintExport');\n\t\ttmpMdwintDiv.style.display = '';\n\n\t\tlet tmpMdwintTextarea = document.getElementById('mdwintConfigOutput');\n\t\ttmpMdwintTextarea.value = tmpMdwintJSON;\n\n\t\t// Build the mdwint CLI command\n\t\tlet tmpMdwintCLI = 'mdwint clone --schema_path ./schema/Model-Extended.json';\n\t\tlet tmpMdwintCLIDiv = document.getElementById('mdwintCLICommand');\n\t\ttmpMdwintCLIDiv.querySelector('div').textContent = tmpMdwintCLI;\n\n\t\t// Provider compatibility note\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tif (tmpProvider !== 'MySQL' && tmpProvider !== 'MSSQL')\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Note: mdwint clone only supports MySQL and MSSQL destinations. The config defaults to MySQL; update the Destination section for your target database.', 'warn');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', '', '');\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Config generated. Save as clone-config.json or copy the one-liner below.', 'ok');\n\t}\n\n\tcopyConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Generate a config first.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpTextarea.value).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'Config copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyCLI()\n\t{\n\t\tlet tmpCmd = document.getElementById('cliCommand').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'CLI command copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyOneShot()\n\t{\n\t\tlet tmpCmd = document.getElementById('cliOneShot').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'One-liner copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tdownloadConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.generateConfig();\n\t\t}\n\t\tlet tmpBlob = new Blob([tmpTextarea.value], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\ttmpAnchor.download = 'clone-config.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Config downloaded as clone-config.json.', 'ok');\n\t}\n\n\tcopyMdwintConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('mdwintConfigOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Generate a config first.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpTextarea.value).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('mdwintConfigStatus', '.meadow.config.json copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyMdwintCLI()\n\t{\n\t\tlet tmpCmd = document.getElementById('mdwintCLICommand').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'mdwint CLI command copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tdownloadMdwintConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('mdwintConfigOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.generateConfig();\n\t\t}\n\t\tlet tmpBlob = new Blob([tmpTextarea.value], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\ttmpAnchor.download = '.meadow.config.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Config downloaded as .meadow.config.json.', 'ok');\n\t}\n}\n\nmodule.exports = DataClonerExportView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Export',\n\tDefaultRenderable: 'DataCloner-Export',\n\tDefaultDestinationAddress: '#DataCloner-Section-Export',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Export',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">6</div>\n\t<div class=\"accordion-card\" id=\"section6\" data-section=\"6\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section6')\">\n\t\t\t<div class=\"accordion-title\">Export Configuration</div>\n\t\t\t<div class=\"accordion-preview\" id=\"preview6\">Generate JSON config for headless cloning</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Generate a JSON config file from your current settings. Use it to run headless clones from the command line.</p>\n\t\t\t<div style=\"display:flex; gap:8px; margin-bottom:10px\">\n\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Export'].generateConfig()\">Generate Config</button>\n\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].copyConfig()\">Copy to Clipboard</button>\n\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].downloadConfig()\">Download JSON</button>\n\t\t\t</div>\n\t\t\t<div id=\"configExportStatus\"></div>\n\t\t\t<div id=\"cliCommand\" style=\"display:none; margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:4px\">CLI Command <span style=\"color:#888; font-weight:normal\">(with config file)</span></label>\n\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer\" onclick=\"pict.views['DataCloner-Export'].copyCLI()\" title=\"Click to copy\"></div>\n\t\t\t</div>\n\t\t\t<div id=\"cliOneShot\" style=\"display:none; margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:4px\">One-liner <span style=\"color:#888; font-weight:normal\">(no config file needed)</span></label>\n\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer; white-space:pre-wrap\" onclick=\"pict.views['DataCloner-Export'].copyOneShot()\" title=\"Click to copy\"></div>\n\t\t\t</div>\n\t\t\t<textarea id=\"configOutput\" style=\"display:none; width:100%; min-height:300px; font-family:monospace; font-size:0.85em; padding:10px; border:1px solid #ccc; border-radius:4px; background:#fafafa; tab-size:4; resize:vertical\" readonly></textarea>\n\n\t\t\t<div id=\"mdwintExport\" style=\"display:none; margin-top:16px; padding-top:16px; border-top:1px solid #eee\">\n\t\t\t\t<h3 style=\"margin:0 0 8px; font-size:1em\">meadow-integration CLI <span style=\"color:#888; font-weight:normal; font-size:0.85em\">(mdwint clone)</span></h3>\n\t\t\t\t<p style=\"font-size:0.85em; color:#666; margin-bottom:8px\">Save as <code>.meadow.config.json</code> in your project root, then run the command below. Requires a local Meadow extended schema JSON file.</p>\n\t\t\t\t<div style=\"display:flex; gap:8px; margin-bottom:10px\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].copyMdwintConfig()\">Copy Config</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].downloadMdwintConfig()\">Download .meadow.config.json</button>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"mdwintCLICommand\" style=\"margin-bottom:10px\">\n\t\t\t\t\t<label style=\"margin-bottom:4px\">CLI Command</label>\n\t\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer\" onclick=\"pict.views['DataCloner-Export'].copyMdwintCLI()\" title=\"Click to copy\"></div>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"mdwintConfigStatus\"></div>\n\t\t\t\t<textarea id=\"mdwintConfigOutput\" style=\"width:100%; min-height:250px; font-family:monospace; font-size:0.85em; padding:10px; border:1px solid #ccc; border-radius:4px; background:#fafafa; tab-size:4; resize:vertical\" readonly></textarea>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Export',\n\t\t\tTemplateHash: 'DataCloner-Export',\n\t\t\tDestinationAddress: '#DataCloner-Section-Export'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],22:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerLayoutView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tonAfterRender()\n\t{\n\t\t// Render all section views into their containers\n\t\tthis.pict.views['DataCloner-Connection'].render();\n\t\tthis.pict.views['DataCloner-Session'].render();\n\t\tthis.pict.views['DataCloner-Schema'].render();\n\t\tthis.pict.views['DataCloner-Deploy'].render();\n\t\tthis.pict.views['DataCloner-Sync'].render();\n\t\tthis.pict.views['DataCloner-Export'].render();\n\t\tthis.pict.views['DataCloner-ViewData'].render();\n\n\t\tthis.pict.CSSMap.injectCSS();\n\t}\n\n\ttoggleSection(pSectionId)\n\t{\n\t\tlet tmpCard = document.getElementById(pSectionId);\n\t\tif (!tmpCard) return;\n\t\ttmpCard.classList.toggle('open');\n\t}\n\n\texpandAllSections()\n\t{\n\t\tlet tmpCards = document.querySelectorAll('.accordion-card');\n\t\tfor (let i = 0; i < tmpCards.length; i++)\n\t\t{\n\t\t\ttmpCards[i].classList.add('open');\n\t\t}\n\t}\n\n\tcollapseAllSections()\n\t{\n\t\tlet tmpCards = document.querySelectorAll('.accordion-card');\n\t\tfor (let i = 0; i < tmpCards.length; i++)\n\t\t{\n\t\t\ttmpCards[i].classList.remove('open');\n\t\t}\n\t}\n\n\ttoggleStatusDetail()\n\t{\n\t\tlet tmpDetail = document.getElementById('liveStatusDetail');\n\t\tlet tmpMeta = document.getElementById('liveStatusMeta');\n\t\tlet tmpMessage = document.getElementById('liveStatusMessage');\n\t\tlet tmpToggle = document.getElementById('liveStatusToggle');\n\t\tlet tmpBar = document.getElementById('liveStatusBar');\n\t\tif (!tmpDetail) return;\n\n\t\tlet tmpIsExpanded = tmpDetail.style.display !== 'none';\n\n\t\tif (tmpIsExpanded)\n\t\t{\n\t\t\ttmpDetail.style.display = 'none';\n\t\t\ttmpMeta.style.display = '';\n\t\t\ttmpMessage.style.display = '';\n\t\t\ttmpToggle.innerHTML = '▼';\n\t\t\ttmpBar.classList.remove('expanded');\n\t\t\tthis.pict.providers.DataCloner.onStatusDetailCollapsed();\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpDetail.style.display = '';\n\t\t\ttmpMeta.style.display = 'none';\n\t\t\ttmpMessage.style.display = 'none';\n\t\t\ttmpToggle.innerHTML = '▲';\n\t\t\ttmpBar.classList.add('expanded');\n\t\t\tthis.pict.providers.DataCloner.onStatusDetailExpanded();\n\t\t}\n\t}\n}\n\nmodule.exports = DataClonerLayoutView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Layout',\n\tDefaultRenderable: 'DataCloner-Layout',\n\tDefaultDestinationAddress: '#DataCloner-Application-Container',\n\tCSS: /*css*/`\n* { box-sizing: border-box; margin: 0; padding: 0; }\nbody { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; color: #333; padding: 20px; }\nh1 { margin-bottom: 20px; color: #1a1a1a; }\nh2 { margin-bottom: 12px; color: #444; font-size: 1.2em; border-bottom: 2px solid #ddd; padding-bottom: 6px; }\n\n.section { background: #fff; border-radius: 8px; padding: 20px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n\n/* Accordion layout */\n.accordion-row { display: flex; gap: 0; margin-bottom: 16px; align-items: stretch; }\n.accordion-number {\n\tflex: 0 0 48px; display: flex; align-items: flex-start; justify-content: center;\n\tpadding-top: 16px; font-size: 1.6em; font-weight: 700; color: #4a90d9;\n\tuser-select: none;\n}\n.accordion-card {\n\tflex: 1; background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n\toverflow: hidden; min-width: 0;\n}\n.accordion-header {\n\tdisplay: flex; align-items: center; padding: 14px 20px; cursor: pointer;\n\tuser-select: none; gap: 12px; transition: background 0.15s; line-height: 1.4;\n}\n.accordion-header:hover { background: #fafafa; }\n.accordion-title { font-weight: 600; color: #333; font-size: 1.05em; white-space: nowrap; }\n.accordion-preview { flex: 1; font-style: italic; color: #888; font-size: 0.9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }\n.accordion-toggle {\n\tflex: 0 0 20px; display: flex; align-items: center; justify-content: center;\n\tborder-radius: 4px; transition: background 0.15s, transform 0.25s; font-size: 0.7em; color: #888;\n}\n.accordion-header:hover .accordion-toggle { background: #eee; color: #555; }\n.accordion-card.open .accordion-toggle { transform: rotate(180deg); }\n.accordion-body { padding: 0 20px 20px; display: none; }\n.accordion-card.open .accordion-body { display: block; }\n.accordion-card.open .accordion-header { border-bottom: 1px solid #eee; }\n.accordion-card.open .accordion-preview { display: none; }\n\n/* Action controls (go link + auto checkbox) */\n.accordion-actions { display: flex; align-items: baseline; gap: 8px; flex-shrink: 0; }\n.accordion-card.open .accordion-actions { display: none; }\n.accordion-go {\n\tfont-size: 0.82em; color: #4a90d9; cursor: pointer; text-decoration: none;\n\tfont-weight: 500; white-space: nowrap; padding: 2px 6px; border-radius: 3px;\n\ttransition: background 0.15s;\n}\n.accordion-go:hover { background: #e8f0fe; text-decoration: underline; }\n.accordion-auto {\n\tfont-size: 0.82em; color: #999; white-space: nowrap; cursor: pointer;\n}\n.accordion-auto .auto-label { display: none; }\n.accordion-auto:hover .auto-label { display: inline; }\n.accordion-auto input[type=\"checkbox\"] { width: auto; margin: 0; cursor: pointer; vertical-align: middle; position: relative; top: 0px; opacity: 0.75; transition: opacity 0.15s; }\n.accordion-auto:hover input[type=\"checkbox\"] { opacity: 1; }\n.accordion-auto:hover { color: #666; }\n\n/* Phase status indicator */\n.accordion-phase {\n\tflex: 0 0 auto; display: none; align-items: center; justify-content: center;\n\tfont-size: 0.85em; line-height: 1;\n}\n.accordion-phase.visible { display: flex; }\n.accordion-phase-ok { color: #28a745; }\n.accordion-phase-error { color: #dc3545; }\n.accordion-phase-busy { color: #28a745; }\n.accordion-phase-busy .phase-spinner {\n\tdisplay: inline-block; width: 14px; height: 14px;\n\tborder: 2px solid #28a745; border-top-color: transparent; border-radius: 50%;\n\tanimation: phase-spin 0.8s linear infinite; vertical-align: middle;\n}\n@keyframes phase-spin {\n\tto { transform: rotate(360deg); }\n}\n\n.accordion-controls {\n\tdisplay: flex; gap: 8px; margin-bottom: 12px; justify-content: flex-end;\n}\n.accordion-controls button {\n\tpadding: 4px 10px; font-size: 0.82em; font-weight: 500; background: none;\n\tborder: 1px solid #ccc; border-radius: 4px; color: #666; cursor: pointer; margin: 0;\n}\n.accordion-controls button:hover { background: #f0f0f0; border-color: #aaa; color: #333; }\n\nlabel { display: block; font-weight: 600; margin-bottom: 4px; font-size: 0.9em; }\ninput[type=\"text\"], input[type=\"password\"], input[type=\"number\"] {\n\twidth: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px;\n\tfont-size: 0.95em; margin-bottom: 10px;\n}\ninput[type=\"text\"]:focus, input[type=\"password\"]:focus, input[type=\"number\"]:focus {\n\toutline: none; border-color: #4a90d9;\n}\n\nbutton {\n\tpadding: 8px 16px; border: none; border-radius: 4px; cursor: pointer;\n\tfont-size: 0.9em; font-weight: 600; margin-right: 8px; margin-bottom: 8px;\n}\nbutton.primary { background: #4a90d9; color: #fff; }\nbutton.primary:hover { background: #357abd; }\nbutton.secondary { background: #6c757d; color: #fff; }\nbutton.secondary:hover { background: #5a6268; }\nbutton.danger { background: #dc3545; color: #fff; }\nbutton.danger:hover { background: #c82333; }\nbutton.success { background: #28a745; color: #fff; }\nbutton.success:hover { background: #218838; }\nbutton:disabled { opacity: 0.5; cursor: not-allowed; }\n\n.status { padding: 8px 12px; border-radius: 4px; margin-top: 10px; font-size: 0.9em; }\n.status.ok { background: #d4edda; color: #155724; }\n.status.error { background: #f8d7da; color: #721c24; }\n.status.info { background: #d1ecf1; color: #0c5460; }\n.status.warn { background: #fff3cd; color: #856404; }\n\n.inline-group { display: flex; gap: 8px; align-items: flex-end; margin-bottom: 10px; }\n.inline-group > div { flex: 1; }\n\na { color: #4a90d9; }\n\nselect { background: #fff; width: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 0.95em; margin-bottom: 10px; }\n\n.checkbox-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }\n.checkbox-row input[type=\"checkbox\"] { width: auto; margin: 0; }\n.checkbox-row label { display: inline; margin: 0; font-weight: normal; cursor: pointer; }\n\n/* Live Status Bar */\n.live-status-bar {\n\tbackground: #fff; border-radius: 8px; margin-bottom: 16px;\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.1);\n\tposition: sticky; top: 0; z-index: 100; border-left: 4px solid #6c757d;\n}\n.live-status-bar.phase-idle { border-left-color: #6c757d; }\n.live-status-bar.phase-disconnected { border-left-color: #dc3545; }\n.live-status-bar.phase-ready { border-left-color: #4a90d9; }\n.live-status-bar.phase-syncing { border-left-color: #28a745; }\n.live-status-bar.phase-stopping { border-left-color: #ffc107; }\n.live-status-bar.phase-complete { border-left-color: #28a745; }\n\n.live-status-dot {\n\twidth: 12px; height: 12px; border-radius: 50%; flex-shrink: 0;\n\tbackground: #6c757d;\n}\n.live-status-bar.phase-idle .live-status-dot { background: #6c757d; }\n.live-status-bar.phase-disconnected .live-status-dot { background: #dc3545; }\n.live-status-bar.phase-ready .live-status-dot { background: #4a90d9; }\n.live-status-bar.phase-syncing .live-status-dot {\n\tbackground: #28a745;\n\tanimation: live-pulse 1.5s ease-in-out infinite;\n}\n.live-status-bar.phase-stopping .live-status-dot {\n\tbackground: #ffc107;\n\tanimation: live-pulse 0.8s ease-in-out infinite;\n}\n.live-status-bar.phase-complete .live-status-dot { background: #28a745; }\n\n@keyframes live-pulse {\n\t0%, 100% { opacity: 1; transform: scale(1); }\n\t50% { opacity: 0.4; transform: scale(0.8); }\n}\n\n.live-status-message { flex: 1; font-size: 0.92em; color: #333; line-height: 1.4; }\n\n.live-status-meta {\n\tdisplay: flex; gap: 16px; flex-shrink: 0; font-size: 0.82em; color: #666;\n}\n.live-status-meta-item { white-space: nowrap; }\n.live-status-meta-item strong { color: #333; }\n\n.live-status-progress-bar {\n\theight: 3px; background: #e9ecef; border-radius: 2px; overflow: hidden;\n\tposition: absolute; bottom: 0; left: 0; right: 0;\n}\n.live-status-progress-fill {\n\theight: 100%; background: #28a745; transition: width 1s ease;\n}\n/* Expandable status bar */\n.live-status-header {\n\tdisplay: flex; align-items: center; gap: 14px; cursor: pointer;\n\tpadding: 14px 20px; user-select: none;\n}\n.live-status-bar.expanded .live-status-header {\n\tborder-bottom: 1px solid #e9ecef; padding-bottom: 10px;\n}\n.live-status-expand-toggle {\n\tflex: 0 0 20px; display: flex; align-items: center; justify-content: center;\n\tfont-size: 0.7em; color: #888; transition: transform 0.25s;\n}\n.live-status-bar.expanded .live-status-expand-toggle { transform: rotate(180deg); }\n\n.live-status-detail {\n\tpadding: 12px 20px 16px; max-height: 60vh; overflow-y: auto;\n}\n\n/* Status Detail Sections */\n.status-detail-section { margin-bottom: 14px; }\n.status-detail-section:last-child { margin-bottom: 0; }\n.status-detail-section-title {\n\tfont-size: 0.85em; font-weight: 600; color: #555; text-transform: uppercase;\n\tletter-spacing: 0.5px; margin-bottom: 8px; padding-bottom: 4px;\n\tborder-bottom: 1px solid #eee;\n}\n\n/* Running Operations */\n.running-op-row {\n\tdisplay: flex; align-items: center; gap: 12px; padding: 6px 0;\n\tfont-size: 0.9em;\n}\n.running-op-name { font-weight: 600; min-width: 180px; }\n.running-op-bar {\n\tflex: 1; height: 8px; background: #e9ecef; border-radius: 4px; overflow: hidden;\n\tmin-width: 120px;\n}\n.running-op-bar-fill { height: 100%; background: #4a90d9; transition: width 0.5s ease; }\n.running-op-count { font-size: 0.85em; color: #666; white-space: nowrap; }\n.running-op-pending { color: #888; font-size: 0.85em; font-style: italic; padding: 4px 0; }\n\n/* Completed Operations */\n.completed-op-row { padding: 8px 0; border-bottom: 1px solid #f0f0f0; }\n.completed-op-row:last-child { border-bottom: none; }\n.completed-op-header {\n\tdisplay: flex; align-items: center; gap: 10px; font-size: 0.9em; margin-bottom: 4px;\n}\n.completed-op-name { font-weight: 600; }\n.completed-op-stats { color: #666; font-size: 0.85em; }\n.completed-op-checkmark { color: #28a745; }\n\n/* Ratio Bar */\n.ratio-bar-container {\n\tdisplay: flex; height: 10px; border-radius: 5px; overflow: hidden;\n\tbackground: #e9ecef; margin: 4px 0;\n}\n.ratio-bar-segment { height: 100%; transition: width 0.5s ease; }\n.ratio-bar-segment.unchanged { background: #6c757d; }\n.ratio-bar-segment.new-records { background: #28a745; }\n.ratio-bar-segment.updated { background: #4a90d9; }\n.ratio-bar-segment.deleted { background: #dc3545; }\n.ratio-bar-legend {\n\tdisplay: flex; gap: 12px; font-size: 0.75em; color: #666; margin-top: 2px; flex-wrap: wrap;\n}\n.ratio-bar-legend-item { display: flex; align-items: center; gap: 4px; }\n.ratio-bar-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }\n.ratio-bar-legend-dot.unchanged-dot { background: #6c757d; }\n.ratio-bar-legend-dot.new-dot { background: #28a745; }\n.ratio-bar-legend-dot.updated-dot { background: #4a90d9; }\n.ratio-bar-legend-dot.deleted-dot { background: #dc3545; }\n\n/* Error Operations */\n.error-op-row { padding: 6px 0; border-bottom: 1px solid #f0f0f0; font-size: 0.9em; }\n.error-op-row:last-child { border-bottom: none; }\n.error-op-header { display: flex; align-items: center; gap: 8px; }\n.error-op-name { font-weight: 600; color: #dc3545; }\n.error-op-status { font-size: 0.82em; color: #dc3545; }\n.error-op-message { font-size: 0.82em; color: #888; margin-top: 2px; padding-left: 18px; }\n.error-op-log-entries {\n\tfont-size: 0.78em; color: #888; margin-top: 4px; padding-left: 18px;\n\tfont-family: monospace; max-height: 80px; overflow-y: auto;\n}\n\n/* Pre-count Table */\n.precount-table {\n\twidth: 100%; border-collapse: collapse; font-size: 0.88em;\n}\n.precount-table thead th {\n\ttext-align: left; font-weight: 600; color: #555; font-size: 0.85em;\n\ttext-transform: uppercase; letter-spacing: 0.3px;\n\tpadding: 4px 8px 6px; border-bottom: 2px solid #e9ecef;\n}\n.precount-table tbody td {\n\tpadding: 4px 8px; border-bottom: 1px solid #f0f0f0;\n}\n.precount-table tbody tr:last-child td { border-bottom: 1px solid #e9ecef; }\n.precount-table tfoot td {\n\tpadding: 6px 8px 2px; font-size: 0.95em;\n}\n.precount-error td { color: #dc3545; }\n.precount-pending {\n\tcolor: #888; font-size: 0.85em; font-style: italic; padding: 8px 0 2px;\n\tdisplay: flex; align-items: center; gap: 6px;\n}\n.precount-spinner {\n\tdisplay: inline-block; width: 12px; height: 12px;\n\tborder: 2px solid #ddd; border-top-color: #4a90d9;\n\tborder-radius: 50%; animation: precount-spin 0.8s linear infinite;\n}\n@keyframes precount-spin { to { transform: rotate(360deg); } }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Layout',\n\t\t\tTemplate: /*html*/`\n<h1>Retold Data Cloner</h1>\n\n<!-- Live Status Bar (Expandable) -->\n<div id=\"liveStatusBar\" class=\"live-status-bar phase-idle\" style=\"position:relative\">\n\t<div class=\"live-status-header\" onclick=\"pict.views['DataCloner-Layout'].toggleStatusDetail()\">\n\t\t<div class=\"live-status-dot\"></div>\n\t\t<div class=\"live-status-message\" id=\"liveStatusMessage\">Idle</div>\n\t\t<div class=\"live-status-meta\" id=\"liveStatusMeta\"></div>\n\t\t<div class=\"live-status-expand-toggle\" id=\"liveStatusToggle\">▼</div>\n\t</div>\n\t<div class=\"live-status-detail\" id=\"liveStatusDetail\" style=\"display:none\">\n\t\t<div id=\"DataCloner-Throughput-Histogram\"></div>\n\t\t<div id=\"DataCloner-StatusDetail-Container\"></div>\n\t</div>\n\t<div class=\"live-status-progress-bar\"><div class=\"live-status-progress-fill\" id=\"liveStatusProgressFill\" style=\"width:0%\"></div></div>\n</div>\n\n<!-- Expand / Collapse All -->\n<div class=\"accordion-controls\">\n\t<button onclick=\"pict.views['DataCloner-Layout'].expandAllSections()\">Expand All</button>\n\t<button onclick=\"pict.views['DataCloner-Layout'].collapseAllSections()\">Collapse All</button>\n</div>\n\n<!-- Section containers -->\n<div id=\"DataCloner-Section-Connection\"></div>\n<div id=\"DataCloner-Section-Session\"></div>\n<div id=\"DataCloner-Section-Schema\"></div>\n<div id=\"DataCloner-Section-Deploy\"></div>\n<div id=\"DataCloner-Section-Sync\"></div>\n<div id=\"DataCloner-Section-Export\"></div>\n<div id=\"DataCloner-Section-ViewData\"></div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Layout',\n\t\t\tTemplateHash: 'DataCloner-Layout',\n\t\t\tDestinationAddress: '#DataCloner-Application-Container'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],23:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerSchemaView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tfetchSchema()\n\t{\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tlet tmpBody = {};\n\t\tif (tmpSchemaURL)\n\t\t{\n\t\t\ttmpBody.SchemaURL = tmpSchemaURL;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetching schema...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/fetch', tmpBody)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.AppData.DataCloner.FetchedTables = pData.Tables || [];\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetched ' + pData.TableCount + ' tables from ' + pData.SchemaURL, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'ok');\n\t\t\t\t\t\tthis.renderTableList();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetch failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'error');\n\t\t\t\t});\n\t}\n\n\tloadSavedSelections()\n\t{\n\t\ttry\n\t\t{\n\t\t\tlet tmpRaw = localStorage.getItem('dataCloner_selectedTables');\n\t\t\tif (tmpRaw)\n\t\t\t{\n\t\t\t\treturn JSON.parse(tmpRaw);\n\t\t\t}\n\t\t}\n\t\tcatch (pError)\n\t\t{\n\t\t\t/* ignore */\n\t\t}\n\t\treturn null;\n\t}\n\n\tsaveSelections()\n\t{\n\t\tlet tmpSelected = this.getSelectedTables();\n\t\tlocalStorage.setItem('dataCloner_selectedTables', JSON.stringify(tmpSelected));\n\t\tthis.updateSelectionCount();\n\t\tthis.pict.providers.DataCloner.updateAllPreviews();\n\t}\n\n\tupdateSelectionCount()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpCount = this.getSelectedTables().length;\n\t\tlet tmpEl = document.getElementById('tableSelectionCount');\n\t\tif (tmpEl)\n\t\t{\n\t\t\ttmpEl.textContent = tmpCount + ' / ' + tmpFetchedTables.length + ' selected';\n\t\t}\n\t}\n\n\trenderTableList()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpContainer = document.getElementById('tableList');\n\t\ttmpContainer.innerHTML = '';\n\n\t\t// Load previously saved selections; if none, default to none checked\n\t\tlet tmpSaved = this.loadSavedSelections();\n\t\tlet tmpSavedSet = null;\n\t\tif (tmpSaved)\n\t\t{\n\t\t\ttmpSavedSet = {};\n\t\t\tfor (let i = 0; i < tmpSaved.length; i++)\n\t\t\t{\n\t\t\t\ttmpSavedSet[tmpSaved[i]] = true;\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpFetchedTables[i];\n\t\t\tlet tmpDiv = document.createElement('div');\n\t\t\ttmpDiv.className = 'table-item';\n\t\t\ttmpDiv.setAttribute('data-table', tmpName.toLowerCase());\n\n\t\t\tlet tmpCheckbox = document.createElement('input');\n\t\t\ttmpCheckbox.type = 'checkbox';\n\t\t\ttmpCheckbox.id = 'tbl_' + tmpName;\n\t\t\ttmpCheckbox.value = tmpName;\n\t\t\t// If we have saved selections, restore them; otherwise default unchecked\n\t\t\ttmpCheckbox.checked = tmpSavedSet ? (tmpSavedSet[tmpName] === true) : false;\n\t\t\ttmpCheckbox.addEventListener('change', () => { this.saveSelections(); });\n\n\t\t\tlet tmpLabel = document.createElement('label');\n\t\t\ttmpLabel.htmlFor = 'tbl_' + tmpName;\n\t\t\ttmpLabel.textContent = tmpName;\n\n\t\t\ttmpDiv.appendChild(tmpCheckbox);\n\t\t\ttmpDiv.appendChild(tmpLabel);\n\t\t\ttmpContainer.appendChild(tmpDiv);\n\t\t}\n\n\t\tdocument.getElementById('tableSelection').style.display = tmpFetchedTables.length > 0 ? 'block' : 'none';\n\t\tdocument.getElementById('tableFilter').value = '';\n\t\tthis.updateSelectionCount();\n\t}\n\n\tfilterTableList()\n\t{\n\t\tlet tmpFilter = document.getElementById('tableFilter').value.toLowerCase().trim();\n\t\tlet tmpItems = document.getElementById('tableList').children;\n\t\tfor (let i = 0; i < tmpItems.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpItems[i].getAttribute('data-table') || '';\n\t\t\ttmpItems[i].style.display = (!tmpFilter || tmpName.indexOf(tmpFilter) >= 0) ? '' : 'none';\n\t\t}\n\t}\n\n\tselectAllTables(pChecked)\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\t// Only affect visible (non-filtered) items\n\t\tlet tmpFilter = document.getElementById('tableFilter').value.toLowerCase().trim();\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpFetchedTables[i];\n\t\t\tif (tmpFilter && tmpName.toLowerCase().indexOf(tmpFilter) < 0)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet tmpCheckbox = document.getElementById('tbl_' + tmpName);\n\t\t\tif (tmpCheckbox)\n\t\t\t{\n\t\t\t\ttmpCheckbox.checked = pChecked;\n\t\t\t}\n\t\t}\n\t\tthis.saveSelections();\n\t}\n\n\tgetSelectedTables()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpSelected = [];\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpCheckbox = document.getElementById('tbl_' + tmpFetchedTables[i]);\n\t\t\tif (tmpCheckbox && tmpCheckbox.checked)\n\t\t\t{\n\t\t\t\ttmpSelected.push(tmpFetchedTables[i]);\n\t\t\t}\n\t\t}\n\t\treturn tmpSelected;\n\t}\n}\n\nmodule.exports = DataClonerSchemaView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Schema',\n\tDefaultRenderable: 'DataCloner-Schema',\n\tDefaultDestinationAddress: '#DataCloner-Section-Schema',\n\tCSS: /*css*/`\n.table-list { max-height: 300px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 8px; margin: 10px 0; }\n.table-item { padding: 4px 8px; display: flex; align-items: center; }\n.table-item:hover { background: #f0f0f0; }\n.table-item input[type=\"checkbox\"] { margin-right: 8px; width: auto; }\n.table-item label { display: inline; font-weight: normal; margin-bottom: 0; cursor: pointer; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Schema',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">3</div>\n\t<div class=\"accordion-card\" id=\"section3\" data-section=\"3\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section3')\">\n\t\t\t<div class=\"accordion-title\">Remote Schema</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase3\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview3\">Fetch and select tables from the remote server</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Schema'].fetchSchema()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto3\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<label for=\"schemaURL\">Schema URL (leave blank for default: /1.0/Retold/Models)</label>\n\t\t\t<input type=\"text\" id=\"schemaURL\" placeholder=\"http://remote-server:8086/1.0/Retold/Models\">\n\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Schema'].fetchSchema()\">Fetch Schema</button>\n\t\t\t<div id=\"schemaStatus\"></div>\n\n\t\t\t<div id=\"tableSelection\" style=\"display:none\">\n\t\t\t\t<h3 style=\"margin:12px 0 8px; font-size:1em;\">Select Tables</h3>\n\t\t\t\t<div style=\"display:flex; gap:8px; align-items:center; margin-bottom:8px\">\n\t\t\t\t\t<input type=\"text\" id=\"tableFilter\" placeholder=\"Filter tables...\" style=\"flex:1; margin-bottom:0\" oninput=\"pict.views['DataCloner-Schema'].filterTableList()\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Schema'].selectAllTables(true)\" style=\"font-size:0.8em\">Select All</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Schema'].selectAllTables(false)\" style=\"font-size:0.8em\">Deselect All</button>\n\t\t\t\t\t<span id=\"tableSelectionCount\" style=\"font-size:0.85em; color:#666; white-space:nowrap\"></span>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"tableList\" class=\"table-list\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Schema',\n\t\t\tTemplateHash: 'DataCloner-Schema',\n\t\t\tDestinationAddress: '#DataCloner-Section-Schema'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],24:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerSessionView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tconfigureSession()\n\t{\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\tif (!tmpServerURL)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Server URL is required.', 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBody = { ServerURL: tmpServerURL.replace(/\\/+$/, '') + '/1.0/' };\n\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim();\n\t\tif (tmpAuthMethod)\n\t\t{\n\t\t\ttmpBody.AuthenticationMethod = tmpAuthMethod;\n\t\t}\n\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI)\n\t\t{\n\t\t\ttmpBody.AuthenticationURITemplate = tmpAuthURI;\n\t\t}\n\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI)\n\t\t{\n\t\t\ttmpBody.CheckSessionURITemplate = tmpCheckURI;\n\t\t}\n\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\tif (tmpCookieName)\n\t\t{\n\t\t\ttmpBody.CookieName = tmpCookieName;\n\t\t}\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr)\n\t\t{\n\t\t\ttmpBody.CookieValueAddress = tmpCookieValueAddr;\n\t\t}\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate)\n\t\t{\n\t\t\ttmpBody.CookieValueTemplate = tmpCookieValueTemplate;\n\t\t}\n\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\tif (tmpLoginMarker)\n\t\t{\n\t\t\ttmpBody.CheckSessionLoginMarker = tmpLoginMarker;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Configuring session...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/configure', tmpBody)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Session configured for ' + pData.ServerURL + ' (domain: ' + pData.DomainMatch + ')', 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Configuration failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tauthenticate()\n\t{\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value.trim();\n\n\t\tif (!tmpUserName || !tmpPassword)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Username and password are required.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authenticating...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/authenticate', { UserName: tmpUserName, Password: tmpPassword })\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success && pData.Authenticated)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authenticated successfully.', 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authentication failed: ' + (pData.Error || 'Not authenticated'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\t\t});\n\t}\n\n\tcheckSession()\n\t{\n\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Checking session...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/session/check')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Authenticated)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session is active. Server: ' + (pData.ServerURL || 'N/A'), 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse if (pData.Configured)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session configured but not authenticated.', 'warn');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'No session configured.', 'warn');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tdeauthenticate()\n\t{\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/deauthenticate')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session deauthenticated.', 'info');\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tgoAction()\n\t{\n\t\t// Two-step: configure session, then authenticate after delay\n\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'busy');\n\t\tthis.configureSession();\n\t\tsetTimeout(\n\t\t\t() =>\n\t\t\t{\n\t\t\t\tthis.authenticate();\n\t\t\t}, 1500);\n\t}\n}\n\nmodule.exports = DataClonerSessionView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Session',\n\tDefaultRenderable: 'DataCloner-Session',\n\tDefaultDestinationAddress: '#DataCloner-Section-Session',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Session',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">2</div>\n\t<div class=\"accordion-card\" id=\"section2\" data-section=\"2\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section2')\">\n\t\t\t<div class=\"accordion-title\">Remote Session</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase2\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview2\">Configure remote server URL and credentials</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Session'].goAction()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto2\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t<label for=\"serverURL\">Remote Server URL</label>\n\t\t\t\t\t<input type=\"text\" id=\"serverURL\" placeholder=\"http://remote-server:8086\" value=\"\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t<label for=\"authMethod\">Auth Method</label>\n\t\t\t\t\t<input type=\"text\" id=\"authMethod\" placeholder=\"get\" value=\"get\">\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<details style=\"margin-bottom:10px\">\n\t\t\t\t<summary style=\"cursor:pointer; font-size:0.9em; color:#666\">Advanced Session Options</summary>\n\t\t\t\t<div style=\"padding:10px 0\">\n\t\t\t\t\t<label for=\"authURI\">Authentication URI Template (leave blank for default)</label>\n\t\t\t\t\t<input type=\"text\" id=\"authURI\" placeholder=\"Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}\">\n\t\t\t\t\t<label for=\"checkURI\">Check Session URI Template</label>\n\t\t\t\t\t<input type=\"text\" id=\"checkURI\" placeholder=\"CheckSession\">\n\t\t\t\t\t<label for=\"cookieName\">Cookie Name</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieName\" placeholder=\"SessionID\" value=\"SessionID\">\n\t\t\t\t\t<label for=\"cookieValueAddr\">Cookie Value Address</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieValueAddr\" placeholder=\"SessionID\" value=\"SessionID\">\n\t\t\t\t\t<label for=\"cookieValueTemplate\">Cookie Value Template (overrides Address if set)</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieValueTemplate\" placeholder=\"{~D:Record.SessionID~}\">\n\t\t\t\t\t<label for=\"loginMarker\">Login Marker</label>\n\t\t\t\t\t<input type=\"text\" id=\"loginMarker\" placeholder=\"LoggedIn\" value=\"LoggedIn\">\n\t\t\t\t</div>\n\t\t\t</details>\n\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Session'].configureSession()\">Configure Session</button>\n\t\t\t<div id=\"sessionConfigStatus\"></div>\n\n\t\t\t<hr style=\"margin:16px 0; border:none; border-top:1px solid #eee\">\n\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div>\n\t\t\t\t\t<label for=\"userName\">Username</label>\n\t\t\t\t\t<input type=\"text\" id=\"userName\" placeholder=\"username\">\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<label for=\"password\">Password</label>\n\t\t\t\t\t<input type=\"password\" id=\"password\" placeholder=\"password\">\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<button class=\"success\" onclick=\"pict.views['DataCloner-Session'].authenticate()\">Authenticate</button>\n\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Session'].checkSession()\">Check Session</button>\n\t\t\t<button class=\"danger\" onclick=\"pict.views['DataCloner-Session'].deauthenticate()\">Deauthenticate</button>\n\t\t\t<div id=\"sessionAuthStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Session',\n\t\t\tTemplateHash: 'DataCloner-Session',\n\t\t\tDestinationAddress: '#DataCloner-Section-Session'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],25:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerSyncView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tstartSync()\n\t{\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\tlet tmpPageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\tlet tmpDateTimePrecisionMS = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (isNaN(tmpDateTimePrecisionMS)) tmpDateTimePrecisionMS = 1000;\n\t\tlet tmpSyncDeletedRecords = document.getElementById('syncDeletedRecords').checked;\n\t\tlet tmpSyncMode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\tlet tmpMaxRecords = parseInt(document.getElementById('syncMaxRecords').value, 10) || 0;\n\t\tlet tmpLogToFile = document.getElementById('syncLogFile').checked;\n\t\tlet tmpAdvancedIDPagination = document.getElementById('syncAdvancedIDPagination').checked;\n\n\t\tif (tmpSelectedTables.length === 0)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('syncStatus', 'No tables selected for sync.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(5, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('syncStatus', 'Starting ' + tmpSyncMode.toLowerCase() + ' sync...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tlet tmpPostBody = { Tables: tmpSelectedTables, PageSize: tmpPageSize, DateTimePrecisionMS: tmpDateTimePrecisionMS, SyncDeletedRecords: tmpSyncDeletedRecords, SyncMode: tmpSyncMode };\n\t\tif (tmpMaxRecords > 0) tmpPostBody.MaxRecordsPerEntity = tmpMaxRecords;\n\t\tif (tmpLogToFile) tmpPostBody.LogToFile = true;\n\t\tif (tmpAdvancedIDPagination) tmpPostBody.UseAdvancedIDPagination = true;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/sync/start', tmpPostBody)\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\tlet tmpMsg = pData.SyncMode + ' sync started for ' + pData.Tables.length + ' tables.';\n\t\t\t\t\tif (pData.SyncDeletedRecords) tmpMsg += ' (including deleted records)';\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', tmpMsg, 'ok');\n\t\t\t\t\ttmpSelf.startPolling();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync start failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t});\n\t}\n\n\tstopSync()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/sync/stop')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync stop requested.', 'warn');\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n\n\tstartPolling()\n\t{\n\t\tif (this.pict.AppData.DataCloner.SyncPollTimer) clearInterval(this.pict.AppData.DataCloner.SyncPollTimer);\n\t\tlet tmpSelf = this;\n\t\tthis.pict.AppData.DataCloner.SyncPollTimer = setInterval(function() { tmpSelf.pollSyncStatus(); }, 2000);\n\t\tthis.pollSyncStatus();\n\t}\n\n\tstopPolling()\n\t{\n\t\tif (this.pict.AppData.DataCloner.SyncPollTimer)\n\t\t{\n\t\t\tclearInterval(this.pict.AppData.DataCloner.SyncPollTimer);\n\t\t\tthis.pict.AppData.DataCloner.SyncPollTimer = null;\n\t\t}\n\t}\n\n\tpollSyncStatus()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/sync/status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.renderSyncProgress(pData);\n\n\t\t\t\tif (!pData.Running && !pData.Stopping)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.stopPolling();\n\t\t\t\t\tif (Object.keys(pData.Tables || {}).length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if any tables had errors or partial sync\n\t\t\t\t\t\tlet tmpTables = pData.Tables || {};\n\t\t\t\t\t\tlet tmpHasErrors = false;\n\t\t\t\t\t\tlet tmpHasPartial = false;\n\t\t\t\t\t\tlet tmpNames = Object.keys(tmpTables);\n\t\t\t\t\t\tfor (let i = 0; i < tmpNames.length; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpTables[tmpNames[i]].Status === 'Error') tmpHasErrors = true;\n\t\t\t\t\t\t\tif (tmpTables[tmpNames[i]].Status === 'Partial') tmpHasPartial = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (tmpHasErrors)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync finished with errors. Check the table below for details.', 'error');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (tmpHasPartial)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync finished. Some records were skipped (GUID conflicts or permission issues).', 'warn');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'ok');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync complete.', 'ok');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'ok');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Fetch the structured report\n\t\t\t\t\t\ttmpSelf.fetchSyncReport();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\t// Silently ignore poll errors\n\t\t\t});\n\t}\n\n\tfetchSyncReport()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/sync/report')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData && pData.ReportVersion)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.LastReport = pData;\n\t\t\t\t\ttmpSelf.renderSyncReport(pData);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\t// Ignore report fetch errors\n\t\t\t});\n\t}\n\n\trenderSyncReport(pReport)\n\t{\n\t\tlet tmpSection = document.getElementById('syncReportSection');\n\t\ttmpSection.style.display = '';\n\n\t\t// --- Summary Cards ---\n\t\tlet tmpCardsContainer = document.getElementById('reportSummaryCards');\n\t\tlet tmpOutcomeClass = 'outcome-' + pReport.Outcome.toLowerCase();\n\t\tlet tmpOutcomeColor = { Success: '#28a745', Partial: '#ffc107', Error: '#dc3545', Stopped: '#6c757d' }[pReport.Outcome] || '#666';\n\n\t\tlet tmpDurationSec = pReport.RunTimestamps.DurationSeconds || 0;\n\t\tlet tmpDurationStr = tmpDurationSec < 60 ? tmpDurationSec + 's' : Math.floor(tmpDurationSec / 60) + 'm ' + (tmpDurationSec % 60) + 's';\n\n\t\tlet tmpTotalSynced = pReport.Summary.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\tlet tmpTotalRecords = pReport.Summary.TotalRecords.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\n\t\ttmpCardsContainer.innerHTML = ''\n\t\t\t+ '<div class=\"report-card ' + tmpOutcomeClass + '\">'\n\t\t\t+ ' <div class=\"card-label\">Outcome</div>'\n\t\t\t+ ' <div class=\"card-value\" style=\"color:' + tmpOutcomeColor + '\">' + pReport.Outcome + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Mode</div>'\n\t\t\t+ ' <div class=\"card-value\">' + pReport.Config.SyncMode + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Duration</div>'\n\t\t\t+ ' <div class=\"card-value\">' + tmpDurationStr + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Tables</div>'\n\t\t\t+ ' <div class=\"card-value\">' + pReport.Summary.Complete + ' / ' + pReport.Summary.TotalTables + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Records</div>'\n\t\t\t+ ' <div class=\"card-value\">' + tmpTotalSynced + '</div>'\n\t\t\t+ ' <div style=\"font-size:0.75em; color:#888\">of ' + tmpTotalRecords + '</div>'\n\t\t\t+ '</div>';\n\n\t\t// --- Anomalies ---\n\t\tlet tmpAnomalyContainer = document.getElementById('reportAnomalies');\n\t\tif (pReport.Anomalies.length === 0)\n\t\t{\n\t\t\ttmpAnomalyContainer.innerHTML = '<div style=\"color:#28a745; font-weight:600; font-size:0.9em\">No anomalies detected.</div>';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpHtml = '<h4 style=\"margin:0 0 8px; color:#dc3545; font-size:0.95em\">Anomalies (' + pReport.Anomalies.length + ')</h4>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Type</th><th>Message</th></tr>';\n\t\t\tfor (let i = 0; i < pReport.Anomalies.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpAnomaly = pReport.Anomalies[i];\n\t\t\t\tlet tmpTypeColor = tmpAnomaly.Type === 'Error' ? '#dc3545' : (tmpAnomaly.Type === 'Partial' ? '#ffc107' : '#6c757d');\n\t\t\t\ttmpHtml += '<tr>';\n\t\t\t\ttmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Table) + '</strong></td>';\n\t\t\t\ttmpHtml += '<td style=\"color:' + tmpTypeColor + '\">' + tmpAnomaly.Type + '</td>';\n\t\t\t\ttmpHtml += '<td>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Message) + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\ttmpAnomalyContainer.innerHTML = tmpHtml;\n\t\t}\n\n\t\t// --- Top Tables by Duration ---\n\t\tlet tmpTopContainer = document.getElementById('reportTopTables');\n\t\tlet tmpTopCount = Math.min(10, pReport.Tables.length);\n\t\tif (tmpTopCount > 0)\n\t\t{\n\t\t\tlet tmpHtml = '<h4 style=\"margin:0 0 8px; font-size:0.95em; color:#444\">Top Tables by Duration</h4>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Duration</th><th>Records</th><th>Status</th></tr>';\n\t\t\tfor (let i = 0; i < tmpTopCount; i++)\n\t\t\t{\n\t\t\t\tlet tmpTable = pReport.Tables[i];\n\t\t\t\tlet tmpDur = tmpTable.DurationSeconds < 60 ? tmpTable.DurationSeconds + 's' : Math.floor(tmpTable.DurationSeconds / 60) + 'm ' + (tmpTable.DurationSeconds % 60) + 's';\n\t\t\t\tlet tmpRecs = tmpTable.Total.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\tlet tmpStatusColor = { Complete: '#28a745', Error: '#dc3545', Partial: '#ffc107' }[tmpTable.Status] || '#666';\n\t\t\t\ttmpHtml += '<tr>';\n\t\t\t\ttmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpTable.Name) + '</strong></td>';\n\t\t\t\ttmpHtml += '<td>' + tmpDur + '</td>';\n\t\t\t\ttmpHtml += '<td>' + tmpRecs + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"color:' + tmpStatusColor + '\">' + tmpTable.Status + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\ttmpTopContainer.innerHTML = tmpHtml;\n\t\t}\n\t}\n\n\tdownloadReport()\n\t{\n\t\tif (!this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'No report available.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpJson = JSON.stringify(this.pict.AppData.DataCloner.LastReport, null, '\\t');\n\t\tlet tmpBlob = new Blob([tmpJson], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\tlet tmpTimestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n\t\ttmpAnchor.download = 'DataCloner-Report-' + tmpTimestamp + '.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'Report downloaded.', 'ok');\n\t}\n\n\tcopyReport()\n\t{\n\t\tif (!this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'No report available.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpJson = JSON.stringify(this.pict.AppData.DataCloner.LastReport, null, '\\t');\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpJson).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('reportStatus', 'Report copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\trenderSyncProgress(pData)\n\t{\n\t\tlet tmpContainer = document.getElementById('syncProgress');\n\t\tlet tmpTables = pData.Tables || {};\n\t\tlet tmpTableNames = Object.keys(tmpTables);\n\n\t\tif (tmpTableNames.length === 0)\n\t\t{\n\t\t\ttmpContainer.innerHTML = '';\n\t\t\treturn;\n\t\t}\n\n\t\t// Categorize tables into sections, preserving original order for pending\n\t\tlet tmpSyncing = [];\n\t\tlet tmpPending = [];\n\t\tlet tmpCompleted = [];\n\t\tlet tmpErrors = [];\n\n\t\tfor (let i = 0; i < tmpTableNames.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpTableNames[i];\n\t\t\tlet tmpTable = tmpTables[tmpName];\n\n\t\t\tif (tmpTable.Status === 'Syncing')\n\t\t\t{\n\t\t\t\ttmpSyncing.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse if (tmpTable.Status === 'Pending')\n\t\t\t{\n\t\t\t\ttmpPending.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse if (tmpTable.Status === 'Complete')\n\t\t\t{\n\t\t\t\ttmpCompleted.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Error, Partial, or anything else\n\t\t\t\ttmpErrors.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t}\n\n\t\tlet tmpHtml = '';\n\t\tlet tmpSelf = this;\n\t\tlet fRenderRow = (pName, pTable) =>\n\t\t{\n\t\t\t// Calculate percentage\n\t\t\tlet tmpPct = 0;\n\t\t\tif (pTable.Total === 0 && (pTable.Status === 'Complete' || pTable.Status === 'Error'))\n\t\t\t{\n\t\t\t\ttmpPct = 100;\n\t\t\t}\n\t\t\telse if (pTable.Total > 0)\n\t\t\t{\n\t\t\t\ttmpPct = Math.round((pTable.Synced / pTable.Total) * 100);\n\t\t\t}\n\n\t\t\t// Color the progress bar based on status\n\t\t\tlet tmpBarColor = '#28a745'; // green\n\t\t\tif (pTable.Status === 'Error') tmpBarColor = '#dc3545';\n\t\t\telse if (pTable.Status === 'Partial') tmpBarColor = '#ffc107';\n\t\t\telse if (pTable.Status === 'Syncing') tmpBarColor = '#4a90d9';\n\t\t\telse if (pTable.Status === 'Pending') tmpBarColor = '#adb5bd';\n\n\t\t\t// Status badge\n\t\t\tlet tmpStatusBadge = pTable.Status;\n\t\t\tif (pTable.Status === 'Complete' && pTable.Total === 0) tmpStatusBadge = 'Complete (empty)';\n\t\t\tif (pTable.Status === 'Partial') tmpStatusBadge = 'Partial \\u26A0';\n\t\t\tif (pTable.Status === 'Error') tmpStatusBadge = 'Error \\u2716';\n\n\t\t\t// Details column\n\t\t\tlet tmpDetails = '';\n\t\t\tif (pTable.ErrorMessage) tmpDetails = pTable.ErrorMessage;\n\t\t\telse if (pTable.Skipped > 0) tmpDetails = pTable.Skipped + ' record(s) skipped';\n\t\t\telse if ((pTable.Errors || 0) > 0) tmpDetails = pTable.Errors + ' error(s)';\n\t\t\telse if (pTable.Status === 'Complete' && pTable.Total === 0) tmpDetails = 'No records on server';\n\t\t\telse if (pTable.Status === 'Complete') tmpDetails = '\\u2714 OK';\n\n\t\t\tlet tmpRow = '<tr>';\n\t\t\ttmpRow += '<td><strong>' + pName + '</strong></td>';\n\t\t\ttmpRow += '<td>' + tmpStatusBadge + '</td>';\n\t\t\ttmpRow += '<td>';\n\t\t\ttmpRow += '<div class=\"progress-bar-container\"><div class=\"progress-bar-fill\" style=\"width:' + tmpPct + '%; background:' + tmpBarColor + '\"></div></div>';\n\t\t\ttmpRow += ' ' + tmpPct + '%';\n\t\t\ttmpRow += '</td>';\n\t\t\ttmpRow += '<td>' + pTable.Synced + ' / ' + pTable.Total + '</td>';\n\t\t\ttmpRow += '<td>' + tmpDetails + '</td>';\n\t\t\ttmpRow += '</tr>';\n\t\t\treturn tmpRow;\n\t\t};\n\n\t\t// === SYNCING — currently active ===\n\t\tif (tmpSyncing.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header\">Syncing</div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpSyncing.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpSyncing[i].Name, tmpSyncing[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// === NEXT UP — pending tables in queue order ===\n\t\tif (tmpPending.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header\">Next Up <span class=\"sync-section-count\">' + tmpPending.length + '</span></div>';\n\t\t\t// Show at most 8 upcoming; collapse the rest\n\t\t\tlet tmpShowCount = Math.min(8, tmpPending.length);\n\t\t\ttmpHtml += '<table class=\"progress-table progress-table-muted\">';\n\t\t\tfor (let i = 0; i < tmpShowCount; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += '<tr><td>' + tmpPending[i].Name + '</td>';\n\t\t\t\tif (tmpPending[i].Data.Total > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpHtml += '<td class=\"sync-pending-count\">' + tmpPending[i].Data.Total.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + ' records</td>';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpHtml += '<td class=\"sync-pending-count\">—</td>';\n\t\t\t\t}\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\tif (tmpPending.length > tmpShowCount)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"sync-section-overflow\">+ ' + (tmpPending.length - tmpShowCount) + ' more table' + (tmpPending.length - tmpShowCount === 1 ? '' : 's') + '</div>';\n\t\t\t}\n\t\t}\n\n\t\t// === ERRORS — failed or partial ===\n\t\tif (tmpErrors.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header sync-section-header-error\">Errors <span class=\"sync-section-count\">' + tmpErrors.length + '</span></div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpErrors.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpErrors[i].Name, tmpErrors[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// === COMPLETED — successful tables ===\n\t\tif (tmpCompleted.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header sync-section-header-ok\">Completed <span class=\"sync-section-count\">' + tmpCompleted.length + '</span></div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpCompleted.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpCompleted[i].Name, tmpCompleted[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\t}\n}\n\nmodule.exports = DataClonerSyncView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Sync',\n\tDefaultRenderable: 'DataCloner-Sync',\n\tDefaultDestinationAddress: '#DataCloner-Section-Sync',\n\tCSS: /*css*/`\n.progress-table { width: 100%; border-collapse: collapse; margin-top: 4px; margin-bottom: 4px; }\n.progress-table th, .progress-table td { text-align: left; padding: 6px 12px; border-bottom: 1px solid #eee; font-size: 0.9em; }\n.progress-table th { background: #f8f9fa; font-weight: 600; }\n.progress-table-muted td { color: #888; padding: 3px 12px; font-size: 0.85em; border-bottom: 1px solid #f4f5f6; }\n.progress-bar-container { width: 120px; height: 16px; background: #e9ecef; border-radius: 8px; overflow: hidden; display: inline-block; vertical-align: middle; }\n.progress-bar-fill { height: 100%; background: #28a745; transition: width 0.3s; }\n.sync-section-header { font-size: 0.8em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: #4a90d9; padding: 10px 0 2px 0; margin-top: 6px; border-top: 1px solid #e0e0e0; }\n.sync-section-header:first-child { border-top: none; margin-top: 10px; }\n.sync-section-header-error { color: #dc3545; }\n.sync-section-header-ok { color: #28a745; }\n.sync-section-count { font-weight: 400; color: #999; font-size: 0.95em; }\n.sync-section-overflow { font-size: 0.8em; color: #aaa; padding: 2px 12px 6px; }\n.sync-pending-count { text-align: right; color: #aaa; font-size: 0.85em; }\n.report-card { background: #f8f9fa; border-radius: 8px; padding: 12px 16px; min-width: 140px; text-align: center; border: 1px solid #e9ecef; }\n.report-card .card-label { font-size: 0.8em; color: #666; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }\n.report-card .card-value { font-size: 1.4em; font-weight: 700; }\n.report-card.outcome-success { border-left: 4px solid #28a745; }\n.report-card.outcome-partial { border-left: 4px solid #ffc107; }\n.report-card.outcome-error { border-left: 4px solid #dc3545; }\n.report-card.outcome-stopped { border-left: 4px solid #6c757d; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Sync',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">5</div>\n\t<div class=\"accordion-card\" id=\"section5\" data-section=\"5\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section5')\">\n\t\t\t<div class=\"accordion-title\">Synchronize Data</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase5\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview5\">Initial sync, page size 100</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Sync'].startSync()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto5\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div style=\"display:flex; gap:8px; align-items:flex-end; margin-bottom:4px\">\n\t\t\t\t<div style=\"flex:0 0 150px\">\n\t\t\t\t\t<label for=\"pageSize\">Page Size</label>\n\t\t\t\t\t<input type=\"number\" id=\"pageSize\" value=\"100\" min=\"1\" max=\"10000\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 220px\">\n\t\t\t\t\t<label for=\"dateTimePrecisionMS\">Timestamp Precision (ms)</label>\n\t\t\t\t\t<input type=\"number\" id=\"dateTimePrecisionMS\" value=\"1000\" min=\"0\" max=\"60000\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; gap:8px\">\n\t\t\t\t\t<button class=\"success\" style=\"margin:0\" onclick=\"pict.views['DataCloner-Sync'].startSync()\">Start Sync</button>\n\t\t\t\t\t<button class=\"danger\" style=\"margin:0\" onclick=\"pict.views['DataCloner-Sync'].stopSync()\">Stop Sync</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div style=\"font-size:0.8em; color:#888; margin-bottom:10px; padding-left:158px\">Cross-DB tolerance for date comparison (default: 1000ms)</div>\n\n\t\t\t<div style=\"margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:6px\">Sync Mode</label>\n\t\t\t\t<div style=\"display:flex; gap:16px; align-items:center\">\n\t\t\t\t\t<label style=\"font-weight:normal; margin:0; cursor:pointer\">\n\t\t\t\t\t\t<input type=\"radio\" name=\"syncMode\" id=\"syncModeInitial\" value=\"Initial\" checked> Initial\n\t\t\t\t\t\t<span style=\"color:#888; font-size:0.85em\">(full clone — download all records)</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t<label style=\"font-weight:normal; margin:0; cursor:pointer\">\n\t\t\t\t\t\t<input type=\"radio\" name=\"syncMode\" id=\"syncModeOngoing\" value=\"Ongoing\"> Ongoing\n\t\t\t\t\t\t<span style=\"color:#888; font-size:0.85em\">(delta — only new/updated records since last sync)</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t<input type=\"checkbox\" id=\"syncDeletedRecords\">\n\t\t\t\t<label for=\"syncDeletedRecords\">Sync deleted records (fetch records marked Deleted=1 on source and mirror locally)</label>\n\t\t\t</div>\n\n\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t<input type=\"checkbox\" id=\"syncAdvancedIDPagination\">\n\t\t\t\t<label for=\"syncAdvancedIDPagination\">Use advanced ID pagination (faster for large tables; uses keyset pagination instead of OFFSET)</label>\n\t\t\t</div>\n\n\t\t\t<div class=\"inline-group\" style=\"margin-top:8px; margin-bottom:4px\">\n\t\t\t\t<div style=\"flex:0 0 200px\">\n\t\t\t\t\t<label for=\"syncMaxRecords\">Max Records per Entity</label>\n\t\t\t\t\t<input type=\"number\" id=\"syncMaxRecords\" value=\"\" min=\"0\" placeholder=\"0 = unlimited\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; align-items:flex-end; padding-bottom:2px\">\n\t\t\t\t\t<div class=\"checkbox-row\" style=\"margin-bottom:0\">\n\t\t\t\t\t\t<input type=\"checkbox\" id=\"syncLogFile\" checked>\n\t\t\t\t\t\t<label for=\"syncLogFile\">Write log file</label>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div id=\"syncStatus\"></div>\n\t\t\t<div id=\"syncProgress\"></div>\n\n\t\t\t<!-- Sync Report (appears after sync completes) -->\n\t\t\t<div id=\"syncReportSection\" style=\"display:none; margin-top:16px; padding-top:16px; border-top:2px solid #ddd\">\n\t\t\t\t<h3 style=\"margin:0 0 12px; font-size:1.1em\">Sync Report</h3>\n\n\t\t\t\t<!-- Summary cards -->\n\t\t\t\t<div id=\"reportSummaryCards\" style=\"display:flex; gap:12px; flex-wrap:wrap; margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Anomalies -->\n\t\t\t\t<div id=\"reportAnomalies\" style=\"margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Top tables by duration -->\n\t\t\t\t<div id=\"reportTopTables\" style=\"margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Buttons -->\n\t\t\t\t<div style=\"display:flex; gap:8px\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Sync'].downloadReport()\">Download Report JSON</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Sync'].copyReport()\">Copy Report</button>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"reportStatus\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Sync',\n\t\t\tTemplateHash: 'DataCloner-Sync',\n\t\t\tDestinationAddress: '#DataCloner-Section-Sync'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],26:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerViewDataView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tpopulateViewTableDropdown()\n\t{\n\t\tlet tmpSelect = document.getElementById('viewTable');\n\t\tif (!tmpSelect) return;\n\t\tlet tmpCurrentValue = tmpSelect.value;\n\n\t\ttmpSelect.innerHTML = '';\n\n\t\tlet tmpDeployedTables = this.pict.AppData.DataCloner.DeployedTables;\n\n\t\tif (!tmpDeployedTables || tmpDeployedTables.length === 0)\n\t\t{\n\t\t\tlet tmpOpt = document.createElement('option');\n\t\t\ttmpOpt.value = '';\n\t\t\ttmpOpt.textContent = '\\u2014 deploy tables first \\u2014';\n\t\t\ttmpSelect.appendChild(tmpOpt);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = 0; i < tmpDeployedTables.length; i++)\n\t\t{\n\t\t\tlet tmpOpt = document.createElement('option');\n\t\t\ttmpOpt.value = tmpDeployedTables[i];\n\t\t\ttmpOpt.textContent = tmpDeployedTables[i];\n\t\t\ttmpSelect.appendChild(tmpOpt);\n\t\t}\n\n\t\t// Restore previous selection if it exists\n\t\tif (tmpCurrentValue)\n\t\t{\n\t\t\ttmpSelect.value = tmpCurrentValue;\n\t\t}\n\t}\n\n\tloadTableData()\n\t{\n\t\tlet tmpTable = document.getElementById('viewTable').value;\n\t\tlet tmpLimit = parseInt(document.getElementById('viewLimit').value, 10) || 100;\n\n\t\tif (!tmpTable)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('viewStatus', 'Select a table first.', 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('viewStatus', 'Loading ' + tmpTable + '...', 'info');\n\t\tdocument.getElementById('viewDataContainer').innerHTML = '';\n\n\t\tlet tmpSelf = this;\n\t\t// Use the standard Meadow CRUD list endpoint: /1.0/{Entity}s/0/{Cap}\n\t\tthis.pict.providers.DataCloner.api('GET', '/1.0/' + tmpTable + 's/0/' + tmpLimit)\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (!Array.isArray(pData))\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', 'Unexpected response (not an array). The table may not be deployed yet.', 'error');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', pData.length + ' row(s) returned' + (pData.length >= tmpLimit ? ' (limit reached \\u2014 increase Max Rows to see more)' : '') + '.', 'ok');\n\t\t\t\ttmpSelf.renderDataTable(pData);\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n\n\trenderDataTable(pRows)\n\t{\n\t\tlet tmpContainer = document.getElementById('viewDataContainer');\n\n\t\tif (!pRows || pRows.length === 0)\n\t\t{\n\t\t\ttmpContainer.innerHTML = '<p style=\"color:#666; font-size:0.9em; padding:8px\">No rows.</p>';\n\t\t\treturn;\n\t\t}\n\n\t\t// Collect all column names from the first row\n\t\tlet tmpColumns = Object.keys(pRows[0]);\n\n\t\tlet tmpHtml = '<table class=\"data-table\">';\n\t\ttmpHtml += '<thead><tr>';\n\t\tfor (let c = 0; c < tmpColumns.length; c++)\n\t\t{\n\t\t\ttmpHtml += '<th>' + this.pict.providers.DataCloner.escapeHtml(tmpColumns[c]) + '</th>';\n\t\t}\n\t\ttmpHtml += '</tr></thead>';\n\n\t\ttmpHtml += '<tbody>';\n\t\tfor (let r = 0; r < pRows.length; r++)\n\t\t{\n\t\t\ttmpHtml += '<tr>';\n\t\t\tfor (let c = 0; c < tmpColumns.length; c++)\n\t\t\t{\n\t\t\t\tlet tmpVal = pRows[r][tmpColumns[c]];\n\t\t\t\tlet tmpDisplay = (tmpVal === null || tmpVal === undefined) ? '' : String(tmpVal);\n\t\t\t\ttmpHtml += '<td title=\"' + this.pict.providers.DataCloner.escapeHtml(tmpDisplay) + '\">' + this.pict.providers.DataCloner.escapeHtml(tmpDisplay) + '</td>';\n\t\t\t}\n\t\t\ttmpHtml += '</tr>';\n\t\t}\n\t\ttmpHtml += '</tbody></table>';\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\t}\n}\n\nmodule.exports = DataClonerViewDataView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-ViewData',\n\tDefaultRenderable: 'DataCloner-ViewData',\n\tDefaultDestinationAddress: '#DataCloner-Section-ViewData',\n\tCSS: /*css*/`\n.data-table { width: 100%; border-collapse: collapse; font-size: 0.8em; font-family: monospace; }\n.data-table th { background: #f8f9fa; font-weight: 600; text-align: left; padding: 4px 8px; border: 1px solid #ddd; white-space: nowrap; position: sticky; top: 0; }\n.data-table td { padding: 4px 8px; border: 1px solid #eee; white-space: nowrap; max-width: 300px; overflow: hidden; text-overflow: ellipsis; }\n.data-table tr:nth-child(even) { background: #fafafa; }\n.data-table tr:hover { background: #f0f7ff; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-ViewData',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">7</div>\n\t<div class=\"accordion-card\" id=\"section7\" data-section=\"7\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section7')\">\n\t\t\t<div class=\"accordion-title\">View Data</div>\n\t\t\t<div class=\"accordion-preview\" id=\"preview7\">Browse synced table data</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t<label for=\"viewTable\">Table</label>\n\t\t\t\t\t<select id=\"viewTable\">\n\t\t\t\t\t\t<option value=\"\">\\u2014 deploy tables first \\u2014</option>\n\t\t\t\t\t</select>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 120px\">\n\t\t\t\t\t<label for=\"viewLimit\">Max Rows</label>\n\t\t\t\t\t<input type=\"number\" id=\"viewLimit\" value=\"100\" min=\"1\" max=\"10000\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; align-items:flex-end\">\n\t\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-ViewData'].loadTableData()\">Load</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div id=\"viewStatus\"></div>\n\t\t\t<div id=\"viewDataContainer\" style=\"overflow-x:auto; margin-top:10px\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-ViewData',\n\t\t\tTemplateHash: 'DataCloner-ViewData',\n\t\t\tDestinationAddress: '#DataCloner-Section-ViewData'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}]},{},[17])(17)\n});\n\n","(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()","module.exports={\n \"name\": \"fable-serviceproviderbase\",\n \"version\": \"3.0.19\",\n \"description\": \"Simple base classes for fable services.\",\n \"main\": \"source/Fable-ServiceProviderBase.js\",\n \"scripts\": {\n \"start\": \"node source/Fable-ServiceProviderBase.js\",\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"types\": \"tsc -p ./tsconfig.build.json\",\n \"check\": \"tsc -p . --noEmit\"\n },\n \"types\": \"types/source/Fable-ServiceProviderBase.d.ts\",\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/stevenvelozo/fable-serviceproviderbase.git\"\n },\n \"keywords\": [\n \"entity\",\n \"behavior\"\n ],\n \"author\": \"Steven Velozo <steven@velozo.com> (http://velozo.com/)\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/fable-serviceproviderbase/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/fable-serviceproviderbase\",\n \"devDependencies\": {\n \"@types/mocha\": \"^10.0.10\",\n \"fable\": \"^3.1.62\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n }\n}\n","/**\n* Fable Service Base\n* @author <steven@velozo.com>\n*/\n\nconst libPackage = require('../package.json');\n\nclass FableServiceProviderBase\n{\n\t/**\n\t * The constructor can be used in two ways:\n\t * 1) With a fable, options object and service hash (the options object and service hash are optional)a\n\t * 2) With an object or nothing as the first parameter, where it will be treated as the options object\n\t *\n\t * @param {import('fable')|Record<string, any>} [pFable] - (optional) The fable instance, or the options object if there is no fable\n\t * @param {Record<string, any>|string} [pOptions] - (optional) The options object, or the service hash if there is no fable\n\t * @param {string} [pServiceHash] - (optional) The service hash to identify this service instance\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t/** @type {import('fable')} */\n\t\tthis.fable;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.options;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.services;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.servicesMap;\n\n\t\t// Check if a fable was passed in; connect it if so\n\t\tif ((typeof(pFable) === 'object') && pFable.isFable)\n\t\t{\n\t\t\tthis.connectFable(pFable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.fable = false;\n\t\t}\n\n\t\t// Initialize the services map if it wasn't passed in\n\t\t/** @type {Record<string, any>} */\n\t\tthis._PackageFableServiceProvider = libPackage;\n\n\t\t// initialize options and UUID based on whether the fable was passed in or not.\n\t\tif (this.fable)\n\t\t{\n\t\t\tthis.UUID = pFable.getUUID();\n\t\t\tthis.options = (typeof(pOptions) === 'object') ? pOptions\n\t\t\t\t\t\t\t: {};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// With no fable, check to see if there was an object passed into either of the first two\n\t\t\t// Parameters, and if so, treat it as the options object\n\t\t\tthis.options = ((typeof(pFable) === 'object') && !pFable.isFable) ? pFable\n\t\t\t\t\t\t\t: (typeof(pOptions) === 'object') ? pOptions\n\t\t\t\t\t\t\t: {};\n\t\t\tthis.UUID = `CORE-SVC-${Math.floor((Math.random() * (99999 - 10000)) + 10000)}`\n\t\t}\n\n\t\t// It's expected that the deriving class will set this\n\t\tthis.serviceType = `Unknown-${this.UUID}`;\n\n\t\t// The service hash is used to identify the specific instantiation of the service in the services map\n\t\tthis.Hash = (typeof(pServiceHash) === 'string') ? pServiceHash \n\t\t\t\t\t: (!this.fable && (typeof(pOptions) === 'string')) ? pOptions\n\t\t\t\t\t: `${this.UUID}`;\n\t}\n\n\t/**\n\t * @param {import('fable')} pFable\n\t */\n\tconnectFable(pFable)\n\t{\n\t\tif ((typeof(pFable) !== 'object') || (!pFable.isFable))\n\t\t{\n\t\t\tlet tmpErrorMessage = `Fable Service Provider Base: Cannot connect to Fable, invalid Fable object passed in. The pFable parameter was a [${typeof(pFable)}].}`;\n\t\t\tconsole.log(tmpErrorMessage);\n\t\t\treturn new Error(tmpErrorMessage);\n\t\t}\n\n\t\tif (!this.fable)\n\t\t{\n\t\t\tthis.fable = pFable;\n\t\t}\n\n\t\tif (!this.log)\n\t\t{\n\t\t\tthis.log = this.fable.Logging;\n\t\t}\n\t\tif (!this.services)\n\t\t{\n\t\t\tthis.services = this.fable.services;\n\t\t}\n\n\t\tif (!this.servicesMap)\n\t\t{\n\t\t\tthis.servicesMap = this.fable.servicesMap;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tstatic isFableService = true;\n}\n\nmodule.exports = FableServiceProviderBase;\n\n// This is left here in case we want to go back to having different code/base class for \"core\" services\nmodule.exports.CoreServiceProviderBase = FableServiceProviderBase;\n","module.exports={\n \"name\": \"pict-application\",\n \"version\": \"1.0.33\",\n \"description\": \"Application base class for a pict view-based application\",\n \"main\": \"source/Pict-Application.js\",\n \"scripts\": {\n \"test\": \"npx quack test\",\n \"start\": \"node source/Pict-Application.js\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-application-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-application-dev -p 30001:8080 -p 38086:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-application\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-application-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-application-dev /bin/bash\",\n \"tests\": \"npx quack test -g\",\n \"lint\": \"eslint source/**\",\n \"types\": \"tsc -p .\"\n },\n \"types\": \"types/source/Pict-Application.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-application.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-application/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-application#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.28.0\",\n \"browser-env\": \"^3.3.0\",\n \"eslint\": \"^9.28.0\",\n \"pict\": \"^1.0.348\",\n \"pict-provider\": \"^1.0.10\",\n \"pict-view\": \"^1.0.66\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"dependencies\": {\n \"fable-serviceproviderbase\": \"^3.0.19\"\n }\n}\n","const libFableServiceBase = require('fable-serviceproviderbase')\n\nconst libPackage = require('../package.json');\n\nconst defaultPictSettings = (\n\t{\n\t\tName: 'DefaultPictApplication',\n\n\t\t// The main \"viewport\" is the view that is used to host our application\n\t\tMainViewportViewIdentifier: 'Default-View',\n\t\tMainViewportRenderableHash: false,\n\t\tMainViewportDestinationAddress: false,\n\t\tMainViewportDefaultDataAddress: false,\n\n\t\t// Whether or not we should automatically render the main viewport and other autorender views after we initialize the pict application\n\t\tAutoSolveAfterInitialize: true,\n\t\tAutoRenderMainViewportViewAfterInitialize: true,\n\t\tAutoRenderViewsAfterInitialize: false,\n\t\tAutoLoginAfterInitialize: false,\n\t\tAutoLoadDataAfterLogin: false,\n\n\t\tConfigurationOnlyViews: [],\n\n\t\tManifests: {},\n\t\t// The prefix to prepend on all template destination hashes\n\t\tIdentifierAddressPrefix: 'PICT-'\n\t});\n\n/**\n * Base class for pict applications.\n */\nclass PictApplication extends libFableServiceBase\n{\n\t/**\n\t * @param {import('fable')} pFable\n\t * @param {Record<string, any>} [pOptions]\n\t * @param {string} [pServiceHash]\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tlet tmpCarryOverConfiguration = (typeof(pFable.settings.PictApplicationConfiguration) === 'object') ? pFable.settings.PictApplicationConfiguration : {};\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictSettings)), tmpCarryOverConfiguration, pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\t/** @type {any} */\n\t\tthis.options;\n\t\t/** @type {any} */\n\t\tthis.log;\n\t\t/** @type {import('pict') & import('fable')} */\n\t\tthis.fable;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {string} */\n\t\tthis.Hash;\n\t\t/**\n\t\t * @type {{ [key: string]: any }}\n\t\t */\n\t\tthis.servicesMap;\n\n\t\tthis.serviceType = 'PictApplication';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\n\t\t// Convenience and consistency naming\n\t\tthis.pict = this.fable;\n\t\t// Wire in the essential Pict state\n\t\t/** @type {Record<string, any>} */\n\t\tthis.AppData = this.fable.AppData;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.Bundle = this.fable.Bundle;\n\n\t\t/** @type {number} */\n\t\tthis.initializeTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastSolvedTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastLoginTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastMarshalFromViewsTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastMarshalToViewsTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastAutoRenderTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastLoadDataTimestamp;\n\n\t\t// Load all the manifests for the application\n\t\tlet tmpManifestKeys = Object.keys(this.options.Manifests);\n\t\tif (tmpManifestKeys.length > 0)\n\t\t{\n\t\t\tfor (let i = 0; i < tmpManifestKeys.length; i++)\n\t\t\t{\n\t\t\t\t// Load each manifest\n\t\t\t\tlet tmpManifestKey = tmpManifestKeys[i];\n\t\t\t\tthis.fable.instantiateServiceProvider('Manifest', this.options.Manifests[tmpManifestKey], tmpManifestKey);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Solve All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonPreSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onPreSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonPreSolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeSolveAsync(fCallback)\n\t{\n\t\tthis.onBeforeSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonSolveAsync(fCallback)\n\t{\n\t\tthis.onSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tsolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing solve() function...`)\n\t\t}\n\n\t\t// Walk through any loaded providers and solve them as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSolve.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpProvidersToSolve.length; i++)\n\t\t{\n\t\t\ttmpProvidersToSolve[i].solve(tmpProvidersToSolve[i]);\n\t\t}\n\n\t\tthis.onBeforeSolve();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t{\n\t\t\t\ttmpViewsToSolve.push(tmpView);\n\t\t\t}\n\t\t}\n\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpViewsToSolve.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\tfor (let i = 0; i < tmpViewsToSolve.length; i++)\n\t\t{\n\t\t\ttmpViewsToSolve[i].solve();\n\t\t}\n\t\tthis.onSolve();\n\t\tthis.onAfterSolve();\n\t\tthis.lastSolvedTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));\n\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\t\t// Walk through any loaded providers and solve them as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSolve.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpProvidersToSolve.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvidersToSolve[i].solveAsync.bind(tmpProvidersToSolve[i]));\n\t\t}\n\n\t\t// Walk through any loaded views and solve them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpViewsToSolve.push(tmpView);\n\t\t\t}\n\t\t}\n\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpViewsToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpViewsToSolve.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToSolve[i].solveAsync.bind(tmpViewsToSolve[i]));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSolvedTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterSolveAsync(fCallback)\n\t{\n\t\tthis.onAfterSolve();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application Login */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tloginAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeLoginAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onLoginAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterLoginAsync.bind(this));\n\n\t\t// check and see if we should automatically trigger a data load\n\t\tif (this.options.AutoLoadDataAfterLogin)\n\t\t{\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tif (!this.isLoggedIn())\n\t\t\t\t{\n\t\t\t\t\treturn fNext();\n\t\t\t\t}\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto loading data after login...`);\n\t\t\t\t}\n\t\t\t\t//TODO: should data load errors funnel here? this creates a weird coupling between login and data load callbacks\n\t\t\t\tthis.loadDataAsync((pError) =>\n\t\t\t\t{\n\t\t\t\t\tfNext(pError);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastLoginTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Check if the application state is logged in. Defaults to true. Override this method in your application based on login requirements.\n\t *\n\t * @return {boolean}\n\t */\n\tisLoggedIn()\n\t{\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application LoadData */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tloadDataAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeLoadDataAsync.bind(this));\n\n\t\t// Walk through any loaded providers and load their data as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToLoadData = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoLoadDataWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToLoadData.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToLoadData.sort((a, b) => { return a.options.AutoLoadDataOrdinal - b.options.AutoLoadDataOrdinal; });\n\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onBeforeLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onLoadDataAsync.bind(this));\n\n\t\t//TODO: think about ways to parallelize these\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onAfterLoadDataAsync.bind(this));\n\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onAfterLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t/** @param {Error} [pError] */\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastLoadDataTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application SaveData */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tsaveDataAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSaveDataAsync.bind(this));\n\n\t\t// Walk through any loaded providers and load their data as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSaveData = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSaveDataWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSaveData.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSaveData.sort((a, b) => { return a.options.AutoSaveDataOrdinal - b.options.AutoSaveDataOrdinal; });\n\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onBeforeSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onSaveDataAsync.bind(this));\n\n\t\t//TODO: think about ways to parallelize these\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onAfterSaveDataAsync.bind(this));\n\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onAfterSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t/** @param {Error} [pError] */\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSaveDataTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialize Application */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\n\t\t\tif ('ConfigurationOnlyViews' in this.options)\n\t\t\t{\n\t\t\t\t// Load all the configuration only views\n\t\t\t\tfor (let i = 0; i < this.options.ConfigurationOnlyViews.length; i++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpViewIdentifier = (typeof(this.options.ConfigurationOnlyViews[i].ViewIdentifier) === 'undefined') ? `AutoView-${this.fable.getUUID()}`\n\t\t\t\t\t\t\t\t\t\t\t: this.options.ConfigurationOnlyViews[i].ViewIdentifier;\n\t\t\t\t\tthis.log.info(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} adding configuration only view: ${tmpViewIdentifier}`);\n\t\t\t\t\tthis.pict.addView(tmpViewIdentifier, this.options.ConfigurationOnlyViews[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.onInitialize();\n\n\t\t\t// Walk through any loaded providers and initialize them as well.\n\t\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\t\tlet tmpProvidersToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\t\tif (tmpProvider.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpProvidersToInitialize.push(tmpProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpProvidersToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpProvidersToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpProvidersToInitialize[i].initialize();\n\t\t\t}\n\n\t\t\t// Now walk through any loaded views and initialize them as well.\n\t\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t\tlet tmpViewsToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpViewsToInitialize.push(tmpView);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpViewsToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpViewsToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpViewsToInitialize[i].initialize();\n\t\t\t}\n\n\t\t\tthis.onAfterInitialize();\n\t\t\tif (this.options.AutoSolveAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto solving after initialization...`);\n\t\t\t\t}\n\t\t\t\t// Solve the template synchronously\n\t\t\t\tthis.solve();\n\t\t\t}\n\t\t\t// Now check and see if we should automatically render as well\n\t\t\tif (this.options.AutoRenderMainViewportViewAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto rendering after initialization...`);\n\t\t\t\t}\n\t\t\t\t// Render the template synchronously\n\t\t\t\tthis.render();\n\t\t\t}\n\t\t\tthis.initializeTimestamp = this.fable.log.getTimeStamp();\n\t\t\tthis.onCompletionOfInitialize();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync:`);\n\t\t}\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 3)\n\t\t\t{\n\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning initialization...`);\n\t\t\t}\n\n\t\t\tif ('ConfigurationOnlyViews' in this.options)\n\t\t\t{\n\t\t\t\t// Load all the configuration only views\n\t\t\t\tfor (let i = 0; i < this.options.ConfigurationOnlyViews.length; i++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpViewIdentifier = (typeof(this.options.ConfigurationOnlyViews[i].ViewIdentifier) === 'undefined') ? `AutoView-${this.fable.getUUID()}`\n\t\t\t\t\t\t\t\t\t\t\t: this.options.ConfigurationOnlyViews[i].ViewIdentifier;\n\t\t\t\t\tthis.log.info(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} adding configuration only view: ${tmpViewIdentifier}`);\n\t\t\t\t\tthis.pict.addView(tmpViewIdentifier, this.options.ConfigurationOnlyViews[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\n\t\t\t// Walk through any loaded providers and solve them as well.\n\t\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\t\tlet tmpProvidersToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\t\tif (tmpProvider.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpProvidersToInitialize.push(tmpProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpProvidersToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpProvidersToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpAnticipate.anticipate(tmpProvidersToInitialize[i].initializeAsync.bind(tmpProvidersToInitialize[i]));\n\t\t\t}\n\n\t\t\t// Now walk through any loaded views and initialize them as well.\n\t\t\t// TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.\n\t\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t\tlet tmpViewsToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpViewsToInitialize.push(tmpView);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the views by their priority\n\t\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\t\ttmpViewsToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpViewsToInitialize.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = tmpViewsToInitialize[i];\n\t\t\t\ttmpAnticipate.anticipate(tmpView.initializeAsync.bind(tmpView));\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\tif (this.options.AutoLoginAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto login (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.loginAsync.bind(this));\n\t\t\t}\n\n\t\t\tif (this.options.AutoSolveAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto solving (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.solveAsync.bind(this));\n\t\t\t}\n\n\t\t\tif (this.options.AutoRenderMainViewportViewAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto rendering (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.renderMainViewportAsync.bind(this));\n\t\t\t}\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync Error: ${pError.message || pError}`, { stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\tthis.initializeTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn tmpCallback();\n\t\t\t\t});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn this.onCompletionOfInitializeAsync(tmpCallback);\n\t\t}\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonCompletionOfInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onCompletionOfInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonCompletionOfInitializeAsync(fCallback)\n\t{\n\t\tthis.onCompletionOfInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal Data From All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tmarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing marshalFromViews() function...`)\n\t\t}\n\t\tthis.onBeforeMarshalFromViews();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalFromViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalFromViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalFromViews.length; i++)\n\t\t{\n\t\t\ttmpViewsToMarshalFromViews[i].marshalFromView();\n\t\t}\n\t\tthis.onMarshalFromViews();\n\t\tthis.onAfterMarshalFromViews();\n\t\tthis.lastMarshalFromViewsTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tmarshalFromViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalFromViewsAsync.bind(this));\n\t\t// Walk through any loaded views and marshalFromViews them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalFromViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalFromViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalFromViews.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToMarshalFromViews[i].marshalFromViewAsync.bind(tmpViewsToMarshalFromViews[i]));\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onMarshalFromViewsAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalFromViewsAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalFromViewsTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal Data To All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tmarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing marshalToViews() function...`)\n\t\t}\n\t\tthis.onBeforeMarshalToViews();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalToViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalToViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalToViews.length; i++)\n\t\t{\n\t\t\ttmpViewsToMarshalToViews[i].marshalToView();\n\t\t}\n\t\tthis.onMarshalToViews();\n\t\tthis.onAfterMarshalToViews();\n\t\tthis.lastMarshalToViewsTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tmarshalToViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalToViewsAsync.bind(this));\n\t\t// Walk through any loaded views and marshalToViews them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalToViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalToViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalToViews.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToMarshalToViews[i].marshalToViewAsync.bind(tmpViewsToMarshalToViews[i]));\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onMarshalToViewsAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalToViewsAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalToViewsTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Render View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeRenderAsync(fCallback)\n\t{\n\t\tthis.onBeforeRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {string} [pViewIdentifier] - The hash of the view to render. By default, the main viewport view is rendered.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string} [pTemplateDataAddress] - The address where the data for the template is stored.\n\t *\n\t * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?\n\t */\n\trender(pViewIdentifier, pRenderableHash, pRenderDestinationAddress, pTemplateDataAddress)\n\t{\n\t\tlet tmpViewIdentifier = (typeof(pViewIdentifier) !== 'string') ? this.options.MainViewportViewIdentifier : pViewIdentifier;\n\t\tlet tmpRenderableHash = (typeof(pRenderableHash) !== 'string') ? this.options.MainViewportRenderableHash : pRenderableHash;\n\t\tlet tmpRenderDestinationAddress = (typeof(pRenderDestinationAddress) !== 'string') ? this.options.MainViewportDestinationAddress : pRenderDestinationAddress;\n\t\tlet tmpTemplateDataAddress = (typeof(pTemplateDataAddress) !== 'string') ? this.options.MainViewportDefaultDataAddress : pTemplateDataAddress;\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} VIEW Renderable[${tmpRenderableHash}] Destination[${tmpRenderDestinationAddress}] TemplateDataAddress[${tmpTemplateDataAddress}] render:`);\n\t\t}\n\n\t\tthis.onBeforeRender();\n\n\t\t// Now get the view (by hash) from the loaded views\n\t\tlet tmpView = (typeof (tmpViewIdentifier) === 'string') ? this.servicesMap.PictView[tmpViewIdentifier] : false;\n\t\tif (!tmpView)\n\t\t{\n\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} could not render from View ${tmpViewIdentifier} because it is not a valid view.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.onRender();\n\n\t\ttmpView.render(tmpRenderableHash, tmpRenderDestinationAddress, tmpTemplateDataAddress);\n\n\t\tthis.onAfterRender();\n\n\t\treturn true;\n\t}\n\t/**\n\t * @return {boolean}\n\t */\n\tonRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonRenderAsync(fCallback)\n\t{\n\t\tthis.onRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {string|((error?: Error) => void)} pViewIdentifier - The hash of the view to render. By default, the main viewport view is rendered. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pRenderableHash] - The hash of the renderable to render. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pRenderDestinationAddress] - The address where the renderable will be rendered. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pTemplateDataAddress] - The address where the data for the template is stored. (or the callback)\n\t * @param {(error?: Error) => void} [fCallback] - The callback, if all other parameters are provided.\n\t *\n\t * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?\n\t */\n\trenderAsync(pViewIdentifier, pRenderableHash, pRenderDestinationAddress, pTemplateDataAddress, fCallback)\n\t{\n\t\tlet tmpViewIdentifier = (typeof(pViewIdentifier) !== 'string') ? this.options.MainViewportViewIdentifier : pViewIdentifier;\n\t\tlet tmpRenderableHash = (typeof(pRenderableHash) !== 'string') ? this.options.MainViewportRenderableHash : pRenderableHash;\n\t\tlet tmpRenderDestinationAddress = (typeof(pRenderDestinationAddress) !== 'string') ? this.options.MainViewportDestinationAddress : pRenderDestinationAddress;\n\t\tlet tmpTemplateDataAddress = (typeof(pTemplateDataAddress) !== 'string') ? this.options.MainViewportDefaultDataAddress : pTemplateDataAddress;\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateDataAddress) === 'function') ? pTemplateDataAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\t(typeof(pViewIdentifier) === 'function') ? pViewIdentifier :\n\t\t\t\t\t\t\tfalse;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} VIEW Renderable[${tmpRenderableHash}] Destination[${tmpRenderDestinationAddress}] TemplateDataAddress[${tmpTemplateDataAddress}] renderAsync:`);\n\t\t}\n\n\t\tlet tmpRenderAnticipate = this.fable.newAnticipate();\n\n\t\ttmpRenderAnticipate.anticipate(this.onBeforeRenderAsync.bind(this));\n\n\t\tlet tmpView = (typeof (tmpViewIdentifier) === 'string') ? this.servicesMap.PictView[tmpViewIdentifier] : false;\n\t\tif (!tmpView)\n\t\t{\n\t\t\tlet tmpErrorMessage = `PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} could not asynchronously render from View ${tmpViewIdentifier} because it is not a valid view.`;\n\t\t\tif (this.pict.LogNoisiness > 3)\n\t\t\t{\n\t\t\t\tthis.log.error(tmpErrorMessage);\n\t\t\t}\n\t\t\treturn tmpCallback(new Error(tmpErrorMessage));\n\t\t}\n\n\t\ttmpRenderAnticipate.anticipate(this.onRenderAsync.bind(this));\n\n\t\ttmpRenderAnticipate.anticipate(\n\t\t\t(fNext) =>\n\t\t\t{\n\t\t\t\ttmpView.renderAsync.call(tmpView, tmpRenderableHash, tmpRenderDestinationAddress, tmpTemplateDataAddress, fNext);\n\t\t\t});\n\n\t\ttmpRenderAnticipate.anticipate(this.onAfterRenderAsync.bind(this));\n\n\t\treturn tmpRenderAnticipate.wait(tmpCallback);\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterRenderAsync(fCallback)\n\t{\n\t\tthis.onAfterRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\trenderMainViewport()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderMainViewport:`);\n\t\t}\n\n\t\treturn this.render();\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\trenderMainViewportAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderMainViewportAsync:`);\n\t\t}\n\n\t\treturn this.renderAsync(fCallback);\n\t}\n\t/**\n\t * @return {void}\n\t */\n\trenderAutoViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning renderAutoViews...`);\n\t\t}\n\t\t// Now walk through any loaded views and sort them by the AutoRender ordinal\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t// Sort the views by their priority\n\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\ttmpLoadedViews.sort((a, b) =>\n\t\t{\n\t\t\treturn this.pict.views[a].options.AutoRenderOrdinal - this.pict.views[b].options.AutoRenderOrdinal;\n\t\t});\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoRender)\n\t\t\t{\n\t\t\t\ttmpView.render();\n\t\t\t}\n\t\t}\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync complete.`);\n\t\t}\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\trenderAutoViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\tfalse;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning renderAutoViewsAsync...`);\n\t\t}\n\n\t\t// Now walk through any loaded views and sort them by the AutoRender ordinal\n\t\t// TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t// Sort the views by their priority\n\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\ttmpLoadedViews.sort((a, b) =>\n\t\t{\n\t\t\treturn this.pict.views[a].options.AutoRenderOrdinal - this.pict.views[b].options.AutoRenderOrdinal;\n\t\t});\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoRender)\n\t\t\t{\n\t\t\t\ttmpAnticipate.anticipate(tmpView.renderAsync.bind(tmpView));\n\t\t\t}\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tthis.lastAutoRenderTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync complete.`);\n\t\t\t\t}\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tget isPictApplication()\n\t{\n\t\treturn true;\n\t}\n}\n\nmodule.exports = PictApplication;\n","module.exports={\n \"name\": \"pict-provider\",\n \"version\": \"1.0.12\",\n \"description\": \"Pict Provider Base Class\",\n \"main\": \"source/Pict-Provider.js\",\n \"scripts\": {\n \"start\": \"node source/Pict-Provider.js\",\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-provider-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-provider-dev -p 24125:8080 -p 30027:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-provider\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-provider-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-provider-dev /bin/bash\",\n \"lint\": \"eslint source/**\",\n \"types\": \"tsc -p .\"\n },\n \"types\": \"types/source/Pict-Provider.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-provider.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-provider/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-provider#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.1\",\n \"eslint\": \"^9.39.1\",\n \"pict\": \"^1.0.351\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"dependencies\": {\n \"fable-serviceproviderbase\": \"^3.0.19\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n }\n}\n","const libFableServiceBase = require('fable-serviceproviderbase');\n\nconst libPackage = require('../package.json');\n\nconst defaultPictProviderSettings = (\n\t{\n\t\tProviderIdentifier: false,\n\n\t\t// If this is set to true, when the App initializes this will.\n\t\t// After the App initializes, initialize will be called as soon as it's added.\n\t\tAutoInitialize: true,\n\t\tAutoInitializeOrdinal: 0,\n\n\t\tAutoLoadDataWithApp: true,\n\t\tAutoLoadDataOrdinal: 0,\n\n\t\tAutoSolveWithApp: true,\n\t\tAutoSolveOrdinal: 0,\n\n\t\tManifests: {},\n\n\t\tTemplates: []\n\t});\n\nclass PictProvider extends libFableServiceBase\n{\n\t/**\n\t * @param {import('fable')} pFable - The Fable instance.\n\t * @param {Record<string, any>} [pOptions] - The options for the provider.\n\t * @param {string} [pServiceHash] - The service hash for the provider.\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t// Intersect default options, parent constructor, service information\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictProviderSettings)), pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\t/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */\n\t\tthis.fable;\n\t\t/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */\n\t\tthis.pict;\n\t\t/** @type {any} */\n\t\tthis.log;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.options;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {string} */\n\t\tthis.Hash;\n\n\t\tif (!this.options.ProviderIdentifier)\n\t\t{\n\t\t\tthis.options.ProviderIdentifier = `AutoProviderID-${this.fable.getUUID()}`;\n\t\t}\n\n\t\tthis.serviceType = 'PictProvider';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\n\t\t// Convenience and consistency naming\n\t\tthis.pict = this.fable;\n\n\t\t// Wire in the essential Pict application state\n\t\t/** @type {Record<string, any>} */\n\t\tthis.AppData = this.pict.AppData;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.Bundle = this.pict.Bundle;\n\n\t\tthis.initializeTimestamp = false;\n\t\tthis.lastSolvedTimestamp = false;\n\n\t\tfor (let i = 0; i < this.options.Templates.length; i++)\n\t\t{\n\t\t\tlet tmpDefaultTemplate = this.options.Templates[i];\n\n\t\t\tif (!tmpDefaultTemplate.hasOwnProperty('Postfix') || !tmpDefaultTemplate.hasOwnProperty('Template'))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} could not load Default Template ${i} in the options array.`, tmpDefaultTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpDefaultTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpDefaultTemplate.Source = `PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix, tmpDefaultTemplate.Postfix, tmpDefaultTemplate.Template, tmpDefaultTemplate.Source);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialization */\n\t/* -------------------------------------------------------------------------- */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-pinitialization.\n\t *\n\t * @return {void}\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\tonInitialize()\n\t{\n\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow PROVIDER [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\t\t\tthis.onInitialize();\n\t\t\tthis.onAfterInitialize();\n\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow PROVIDER [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initializeAsync:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.info(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} beginning initialization...`);\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialization failed: ${pError.message || pError}`, { Stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\telse if (this.pict.LogNoisiness > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.info(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fCallback();\n\t\t\t\t})\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn fCallback();\n\t\t}\n\t}\n\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\tonPreRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onPreRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-render.\n\t *\n\t * @return {void}\n\t */\n\tonPreRenderAsync(fCallback)\n\t{\n\t\tthis.onPreRender();\n\t\treturn fCallback();\n\t}\n\n\trender()\n\t{\n\t\treturn this.onPreRender();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after render.\n\t *\n\t * @return {void}\n\t */\n\trenderAsync(fCallback)\n\t{\n\t\tthis.onPreRender();\n\t\treturn fCallback();\n\t}\n\n\tonPreSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onPreSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-solve.\n\t *\n\t * @return {void}\n\t */\n\tonPreSolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\tsolve()\n\t{\n\t\treturn this.onPreSolve();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after solve.\n\t *\n\t * @return {void}\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.\n\t */\n\tonBeforeLoadDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Hook to allow the provider to load data during application data load.\n\t *\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.\n\t */\n\tonLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.\n\t */\n\tonAfterLoadDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.\n\t *\n\t * @return {void}\n\t */\n\tonBeforeSaveDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Hook to allow the provider to load data during application data load.\n\t *\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.\n\t *\n\t * @return {void}\n\t */\n\tonSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.\n\t *\n\t * @return {void}\n\t */\n\tonAfterSaveDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n}\n\nmodule.exports = PictProvider;\n","module.exports = (\n{\n\t\"RenderOnLoad\": true,\n\n\t\"DefaultRenderable\": \"Histogram-Wrap\",\n\t\"DefaultDestinationAddress\": \"#Histogram-Container-Div\",\n\n\t\"Templates\":\n\t[\n\t\t{\n\t\t\t\"Hash\": \"Histogram-Container\",\n\t\t\t\"Template\": \"<!-- Histogram Container Rendering Soon -->\"\n\t\t}\n\t],\n\n\t\"Renderables\":\n\t[\n\t\t{\n\t\t\t\"RenderableHash\": \"Histogram-Wrap\",\n\t\t\t\"TemplateHash\": \"Histogram-Container\",\n\t\t\t\"DestinationAddress\": \"#Histogram-Container-Div\"\n\t\t}\n\t],\n\n\t\"TargetElementAddress\": \"#Histogram-Container-Div\",\n\n\t// --- Data Configuration ---\n\n\t// Address in AppData (or other Pict address space) for the histogram bins\n\t// Expected format: Array of objects with at least { Label, Value } properties\n\t// e.g. [{ Label: \"2020\", Value: 15 }, { Label: \"2021\", Value: 42 }]\n\t\"DataAddress\": false,\n\n\t// Alternatively, provide bins directly (used if DataAddress is not set)\n\t\"Bins\": [],\n\n\t// Property names within each bin object\n\t\"LabelProperty\": \"Label\",\n\t\"ValueProperty\": \"Value\",\n\n\t// --- Layout Configuration ---\n\n\t// \"vertical\" = bars grow upward; \"horizontal\" = bars grow rightward\n\t\"Orientation\": \"vertical\",\n\n\t// The rendering mode: \"browser\", \"consoleui\", or \"cli\"\n\t// \"browser\" renders HTML/CSS/SVG; \"consoleui\" renders via blessed widgets;\n\t// \"cli\" renders ANSI text to stdout\n\t\"RenderMode\": \"browser\",\n\n\t// Maximum height in pixels (browser vertical) or characters (cli/consoleui)\n\t\"MaxBarSize\": 200,\n\n\t// Bar thickness in pixels (browser) or characters (cli/consoleui)\n\t\"BarThickness\": 30,\n\n\t// Gap between bars in pixels (browser) or characters (cli/consoleui)\n\t\"BarGap\": 4,\n\n\t// When true, bar groups expand to fill the container width (vertical) or\n\t// height (horizontal) using CSS flex-grow instead of a fixed BarThickness.\n\t// Labels and values overflow their column so they remain readable even when\n\t// bars are very narrow. Best suited for time-series or dense histograms.\n\t\"FillContainer\": false,\n\n\t// Whether to show value labels on/above bars\n\t\"ShowValues\": true,\n\n\t// Whether to show bin labels (x-axis for vertical, y-axis for horizontal)\n\t\"ShowLabels\": true,\n\n\t// In FillContainer mode, controls label density in the separate label row.\n\t// 0 = auto-compute (space labels approximately 80px apart based on container\n\t// width), N > 0 = show a label every N bars starting from index 0.\n\t// Ignored when FillContainer is false (every bar shows its own label).\n\t\"LabelInterval\": 0,\n\n\t// Color of the bars (CSS color for browser, ANSI color name for cli/consoleui)\n\t\"BarColor\": \"#4A90D9\",\n\n\t// Color of selected bars\n\t\"SelectedBarColor\": \"#2ECC71\",\n\n\t// Color of bars in the selection range\n\t\"SelectionRangeColor\": \"#85C1E9\",\n\n\t// --- Selection Configuration ---\n\n\t// Enable selection mode\n\t\"Selectable\": false,\n\n\t// Selection mode: \"single\", \"multiple\", \"range\"\n\t// \"single\" - click to select one bar\n\t// \"multiple\" - click to toggle individual bars\n\t// \"range\" - drag sliders to select a contiguous range of bins\n\t\"SelectionMode\": \"range\",\n\n\t// Address in AppData to write selection state\n\t// Will contain { SelectedIndices: [], RangeStart: N, RangeEnd: N } or similar\n\t\"SelectionDataAddress\": false,\n\n\t// Initial selection (array of indices or { Start, End } for range mode)\n\t\"InitialSelection\": null,\n\n\t// --- CLI/ConsoleUI Configuration ---\n\n\t// Characters used for rendering in text mode\n\t\"BarCharacter\": \"\\u2588\",\n\t\"BarPartialCharacters\": [\" \", \"\\u2581\", \"\\u2582\", \"\\u2583\", \"\\u2584\", \"\\u2585\", \"\\u2586\", \"\\u2587\", \"\\u2588\"],\n\t\"EmptyCharacter\": \" \",\n\t\"SliderCharacter\": \"\\u2502\",\n\t\"SliderHandleCharacter\": \"\\u25C6\",\n\n\t// Width of the histogram in characters (cli/consoleui)\n\t\"TextWidth\": 60,\n\n\t// Height of the histogram in characters (cli/consoleui vertical)\n\t\"TextHeight\": 15,\n\n\t// --- CSS ---\n\t\"CSS\": `.pict-histogram-container\n{\n\tdisplay: inline-block;\n\tposition: relative;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n\tfont-size: 12px;\n\tuser-select: none;\n}\n.pict-histogram-chart\n{\n\tdisplay: flex;\n\talign-items: flex-end;\n\tposition: relative;\n}\n.pict-histogram-container.pict-histogram-horizontal\n{\n\tdisplay: inline-flex;\n\tflex-direction: row;\n\talign-items: stretch;\n}\n.pict-histogram-chart.pict-histogram-horizontal\n{\n\tflex-direction: column;\n\talign-items: flex-start;\n}\n.pict-histogram-bar-group\n{\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tcursor: default;\n\tflex-shrink: 0;\n}\n.pict-histogram-horizontal .pict-histogram-bar-group\n{\n\tflex-direction: row;\n\talign-items: center;\n}\n.pict-histogram-bar\n{\n\ttransition: background-color 0.15s ease, height 0.2s ease, width 0.2s ease;\n\tborder-radius: 2px 2px 0 0;\n\tmin-width: 1px;\n\tmin-height: 1px;\n}\n.pict-histogram-horizontal .pict-histogram-bar\n{\n\tborder-radius: 0 2px 2px 0;\n}\n.pict-histogram-bar.pict-histogram-selectable\n{\n\tcursor: pointer;\n}\n.pict-histogram-bar.pict-histogram-selectable:hover\n{\n\topacity: 0.8;\n}\n.pict-histogram-bar.pict-histogram-selected\n{\n\tbox-shadow: 0 0 0 2px rgba(46, 204, 113, 0.4);\n}\n.pict-histogram-bar.pict-histogram-in-range\n{\n\topacity: 0.9;\n}\n.pict-histogram-value-label\n{\n\ttext-align: center;\n\tcolor: #666;\n\tfont-size: 11px;\n\tpadding: 2px 0;\n\twhite-space: nowrap;\n}\n.pict-histogram-horizontal .pict-histogram-value-label\n{\n\tpadding: 0 4px;\n}\n.pict-histogram-bin-label\n{\n\ttext-align: center;\n\tcolor: #333;\n\tfont-size: 11px;\n\tpadding: 4px 2px 0 2px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n.pict-histogram-horizontal .pict-histogram-bin-label\n{\n\tpadding: 0 4px 0 0;\n\ttext-align: right;\n\tmin-width: 40px;\n}\n.pict-histogram-range-slider-container\n{\n\tposition: relative;\n\twidth: 100%;\n\theight: 24px;\n\tmargin-top: 4px;\n}\n.pict-histogram-horizontal .pict-histogram-range-slider-container\n{\n\twidth: 24px;\n\theight: auto;\n\talign-self: stretch;\n\tmargin-top: 0;\n\tmargin-left: 4px;\n}\n.pict-histogram-range-track\n{\n\tposition: absolute;\n\ttop: 10px;\n\tleft: 0;\n\tright: 0;\n\theight: 4px;\n\tbackground: #E0E0E0;\n\tborder-radius: 2px;\n}\n.pict-histogram-horizontal .pict-histogram-range-track\n{\n\ttop: 0;\n\tleft: 10px;\n\tright: auto;\n\tbottom: 0;\n\twidth: 4px;\n\theight: auto;\n}\n.pict-histogram-range-fill\n{\n\tposition: absolute;\n\ttop: 10px;\n\theight: 4px;\n\tbackground: #4A90D9;\n\tborder-radius: 2px;\n}\n.pict-histogram-horizontal .pict-histogram-range-fill\n{\n\ttop: auto;\n\tleft: 10px;\n\twidth: 4px;\n\theight: auto;\n}\n.pict-histogram-range-handle\n{\n\tposition: absolute;\n\ttop: 4px;\n\twidth: 16px;\n\theight: 16px;\n\tbackground: #fff;\n\tborder: 2px solid #4A90D9;\n\tborder-radius: 50%;\n\tcursor: grab;\n\tz-index: 2;\n\ttransform: translateX(-50%);\n}\n.pict-histogram-horizontal .pict-histogram-range-handle\n{\n\ttop: auto;\n\tleft: 4px;\n\ttransform: translateY(-50%);\n}\n.pict-histogram-range-handle:active\n{\n\tcursor: grabbing;\n\tbackground: #4A90D9;\n}\n.pict-histogram-range-handle:active,\n.pict-histogram-range-handle:focus\n{\n\tbox-shadow: 0 0 0 3px rgba(74, 144, 217, 0.3);\n\toutline: none;\n}\n.pict-histogram-container.pict-histogram-fill\n{\n\tdisplay: block;\n\twidth: 100%;\n}\n.pict-histogram-fill .pict-histogram-chart\n{\n\twidth: 100%;\n}\n.pict-histogram-fill .pict-histogram-bar-group\n{\n\tflex: 1 1 0%;\n\tmin-width: 0;\n}\n.pict-histogram-fill .pict-histogram-bar\n{\n\twidth: 100%;\n}\n.pict-histogram-axis-line\n{\n\twidth: 100%;\n\theight: 1px;\n\tbackground: #ccc;\n}\n.pict-histogram-label-row\n{\n\tdisplay: flex;\n\twidth: 100%;\n}\n.pict-histogram-fill-label\n{\n\tfont-size: 10px;\n\tcolor: #666;\n\ttext-align: center;\n\twhite-space: nowrap;\n\toverflow: visible;\n\tline-height: 16px;\n}\n`\n});\n","/**\n * Pict Section Histogram\n *\n * A histogram visualization section for the Pict MVC framework.\n *\n * Supports:\n * - Vertical and horizontal orientation\n * - Three render modes: browser (HTML/CSS), consoleui (blessed), cli (ANSI)\n * - Interactive selection: single click, multi-select, or range slider\n * - Data binding via Pict AppData addresses\n *\n * @module pict-section-histogram\n */\n\nconst libPictViewClass = require('pict-view');\nconst _DefaultConfiguration = require('./Pict-Section-Histogram-DefaultConfiguration.js');\n\nconst libRendererBrowser = require('./renderers/Pict-Histogram-Renderer-Browser.js');\nconst libRendererConsoleUI = require('./renderers/Pict-Histogram-Renderer-ConsoleUI.js');\nconst libRendererCLI = require('./renderers/Pict-Histogram-Renderer-CLI.js');\n\nclass PictSectionHistogram extends libPictViewClass\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tlet tmpOptions = Object.assign({}, _DefaultConfiguration, pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\tthis.initialRenderComplete = false;\n\n\t\t// --- Selection State ---\n\n\t\t// Set of selected bin indices (for \"single\" and \"multiple\" modes)\n\t\tthis._selectedIndices = new Set();\n\n\t\t// Range bounds (for \"range\" mode)\n\t\tthis._selectionRangeStart = 0;\n\t\tthis._selectionRangeEnd = 0;\n\n\t\t// Resolve the renderer for the configured mode\n\t\tthis._renderer = this._resolveRenderer();\n\n\t\t// Apply initial selection if provided\n\t\tthis._applyInitialSelection();\n\t}\n\n\t/**\n\t * Set up the initial selection state from options.\n\t */\n\t_applyInitialSelection()\n\t{\n\t\tif (this.options.InitialSelection)\n\t\t{\n\t\t\tthis.setSelection(this.options.InitialSelection);\n\t\t}\n\t\telse if (this.options.Selectable && this.options.SelectionMode === 'range')\n\t\t{\n\t\t\t// Default: select all bins\n\t\t\tlet tmpBins = this.getBins();\n\t\t\tthis._selectionRangeStart = 0;\n\t\t\tthis._selectionRangeEnd = Math.max(0, tmpBins.length - 1);\n\t\t\tthis._syncSelectionFromRange();\n\t\t}\n\t}\n\n\t/**\n\t * Pick the renderer module based on RenderMode option.\n\t *\n\t * @returns {object} The renderer module { render, wireEvents }\n\t */\n\t_resolveRenderer()\n\t{\n\t\tswitch (this.options.RenderMode)\n\t\t{\n\t\t\tcase 'consoleui':\n\t\t\t\treturn libRendererConsoleUI;\n\t\t\tcase 'cli':\n\t\t\t\treturn libRendererCLI;\n\t\t\tcase 'browser':\n\t\t\tdefault:\n\t\t\t\treturn libRendererBrowser;\n\t\t}\n\t}\n\n\t// --- Data Access ---\n\n\t/**\n\t * Get the current bin data array.\n\t *\n\t * Reads from the configured DataAddress in AppData, falling back to\n\t * the static Bins option.\n\t *\n\t * @returns {Array} Array of bin objects\n\t */\n\tgetBins()\n\t{\n\t\tif (this.options.DataAddress)\n\t\t{\n\t\t\tconst tmpAddressSpace =\n\t\t\t{\n\t\t\t\tFable: this.fable,\n\t\t\t\tPict: this.fable,\n\t\t\t\tAppData: this.AppData,\n\t\t\t\tBundle: this.Bundle,\n\t\t\t\tOptions: this.options\n\t\t\t};\n\t\t\tlet tmpData = this.fable.manifest.getValueByHash(tmpAddressSpace, this.options.DataAddress);\n\t\t\tif (Array.isArray(tmpData))\n\t\t\t{\n\t\t\t\treturn tmpData;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis.log.warn(`PICT-Histogram DataAddress [${this.options.DataAddress}] did not return an array.`);\n\t\t\t}\n\t\t}\n\n\t\treturn this.options.Bins || [];\n\t}\n\n\t/**\n\t * Set the bins programmatically (updates the Bins option).\n\t *\n\t * @param {Array} pBins - Array of bin objects { Label, Value, ... }\n\t */\n\tsetBins(pBins)\n\t{\n\t\tif (!Array.isArray(pBins))\n\t\t{\n\t\t\tthis.log.warn('PICT-Histogram setBins requires an array.');\n\t\t\treturn;\n\t\t}\n\t\tthis.options.Bins = pBins;\n\n\t\t// If we also have a DataAddress, write through\n\t\tif (this.options.DataAddress)\n\t\t{\n\t\t\tconst tmpAddressSpace =\n\t\t\t{\n\t\t\t\tFable: this.fable,\n\t\t\t\tPict: this.fable,\n\t\t\t\tAppData: this.AppData,\n\t\t\t\tBundle: this.Bundle,\n\t\t\t\tOptions: this.options\n\t\t\t};\n\t\t\tthis.fable.manifest.setValueByHash(tmpAddressSpace, this.options.DataAddress, pBins);\n\t\t}\n\t}\n\n\t// --- Selection Logic ---\n\n\t/**\n\t * Check whether a bin index is currently selected.\n\t *\n\t * @param {number} pIndex\n\t * @returns {boolean}\n\t */\n\tisIndexSelected(pIndex)\n\t{\n\t\tif (!this.options.Selectable)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\treturn (pIndex === this._selectionRangeStart || pIndex === this._selectionRangeEnd);\n\t\t}\n\n\t\treturn this._selectedIndices.has(pIndex);\n\t}\n\n\t/**\n\t * Check whether a bin index falls within the current range selection\n\t * (but is not one of the range endpoints).\n\t *\n\t * @param {number} pIndex\n\t * @returns {boolean}\n\t */\n\tisIndexInRange(pIndex)\n\t{\n\t\tif (!this.options.Selectable || this.options.SelectionMode !== 'range')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn (pIndex > this._selectionRangeStart && pIndex < this._selectionRangeEnd);\n\t}\n\n\t/**\n\t * Get the current selection state.\n\t *\n\t * @returns {object} Selection descriptor\n\t */\n\tgetSelection()\n\t{\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\tlet tmpBins = this.getBins();\n\t\t\tlet tmpIndices = [];\n\t\t\tfor (let i = this._selectionRangeStart; i <= this._selectionRangeEnd; i++)\n\t\t\t{\n\t\t\t\ttmpIndices.push(i);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tMode: 'range',\n\t\t\t\tRangeStart: this._selectionRangeStart,\n\t\t\t\tRangeEnd: this._selectionRangeEnd,\n\t\t\t\tSelectedIndices: tmpIndices,\n\t\t\t\tStartLabel: (tmpBins[this._selectionRangeStart] || {})[this.options.LabelProperty],\n\t\t\t\tEndLabel: (tmpBins[this._selectionRangeEnd] || {})[this.options.LabelProperty]\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn {\n\t\t\t\tMode: this.options.SelectionMode,\n\t\t\t\tSelectedIndices: Array.from(this._selectedIndices).sort((a, b) => a - b)\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Programmatically set the selection.\n\t *\n\t * @param {object|Array} pSelection - For range: { Start, End }; for single/multiple: array of indices\n\t */\n\tsetSelection(pSelection)\n\t{\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\tif (pSelection && typeof (pSelection.Start) === 'number' && typeof (pSelection.End) === 'number')\n\t\t\t{\n\t\t\t\tthis._selectionRangeStart = pSelection.Start;\n\t\t\t\tthis._selectionRangeEnd = pSelection.End;\n\t\t\t\tthis._syncSelectionFromRange();\n\t\t\t}\n\t\t}\n\t\telse if (Array.isArray(pSelection))\n\t\t{\n\t\t\tthis._selectedIndices = new Set(pSelection);\n\t\t}\n\n\t\tthis._writeSelectionToAddress();\n\t}\n\n\t/**\n\t * Handle a bar click in single or multiple selection mode.\n\t *\n\t * @param {number} pIndex - The clicked bin index\n\t */\n\thandleBarClick(pIndex)\n\t{\n\t\tif (this.options.SelectionMode === 'single')\n\t\t{\n\t\t\tthis._selectedIndices.clear();\n\t\t\tthis._selectedIndices.add(pIndex);\n\t\t}\n\t\telse if (this.options.SelectionMode === 'multiple')\n\t\t{\n\t\t\tif (this._selectedIndices.has(pIndex))\n\t\t\t{\n\t\t\t\tthis._selectedIndices.delete(pIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis._selectedIndices.add(pIndex);\n\t\t\t}\n\t\t}\n\n\t\tthis._writeSelectionToAddress();\n\t\tthis.onSelectionChange(this.getSelection());\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Handle a bar click in range mode — moves the nearest handle.\n\t *\n\t * @param {number} pIndex - The clicked bin index\n\t */\n\thandleRangeBarClick(pIndex)\n\t{\n\t\tlet tmpDistStart = Math.abs(pIndex - this._selectionRangeStart);\n\t\tlet tmpDistEnd = Math.abs(pIndex - this._selectionRangeEnd);\n\n\t\tif (tmpDistStart <= tmpDistEnd)\n\t\t{\n\t\t\tthis._selectionRangeStart = Math.min(pIndex, this._selectionRangeEnd);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis._selectionRangeEnd = Math.max(pIndex, this._selectionRangeStart);\n\t\t}\n\n\t\tthis._syncSelectionFromRange();\n\t\tthis._writeSelectionToAddress();\n\t\tthis.onSelectionChange(this.getSelection());\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Sync _selectedIndices from the range bounds (so getSelection is consistent).\n\t */\n\t_syncSelectionFromRange()\n\t{\n\t\tthis._selectedIndices.clear();\n\t\tfor (let i = this._selectionRangeStart; i <= this._selectionRangeEnd; i++)\n\t\t{\n\t\t\tthis._selectedIndices.add(i);\n\t\t}\n\t}\n\n\t/**\n\t * Write the current selection state to the configured SelectionDataAddress.\n\t */\n\t_writeSelectionToAddress()\n\t{\n\t\tif (!this.options.SelectionDataAddress)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tconst tmpAddressSpace =\n\t\t{\n\t\t\tFable: this.fable,\n\t\t\tPict: this.fable,\n\t\t\tAppData: this.AppData,\n\t\t\tBundle: this.Bundle,\n\t\t\tOptions: this.options\n\t\t};\n\n\t\tthis.fable.manifest.setValueByHash(tmpAddressSpace, this.options.SelectionDataAddress, this.getSelection());\n\t}\n\n\t/**\n\t * Hook for subclasses or consumers to react to selection changes.\n\t *\n\t * @param {object} pSelection - The new selection state\n\t */\n\tonSelectionChange(pSelection)\n\t{\n\t\t// Override in subclass or assign externally\n\t}\n\n\t// --- Lifecycle Hooks ---\n\n\tonBeforeInitialize()\n\t{\n\t\tsuper.onBeforeInitialize();\n\t\treturn super.onBeforeInitialize();\n\t}\n\n\tonAfterRender(pRenderable)\n\t{\n\t\t// Inject CSS\n\t\tthis.pict.CSSMap.injectCSS();\n\n\t\tif (!this.initialRenderComplete)\n\t\t{\n\t\t\tthis.onAfterInitialRender();\n\t\t\tthis.initialRenderComplete = true;\n\t\t}\n\n\t\treturn super.onAfterRender(pRenderable);\n\t}\n\n\tonAfterInitialRender()\n\t{\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Render the histogram using the active renderer and wire events.\n\t */\n\trenderHistogram()\n\t{\n\t\t// Ensure CSS is injected (covers both lifecycle and direct calls)\n\t\tif (this.pict.CSSMap)\n\t\t{\n\t\t\tthis.pict.CSSMap.injectCSS();\n\t\t}\n\t\tthis._renderer.render(this);\n\t\tthis._renderer.wireEvents(this);\n\t\tthis.initialRenderComplete = true;\n\t}\n\n\t// --- Data Marshaling ---\n\n\tmarshalToView()\n\t{\n\t\tsuper.marshalToView();\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\tmarshalFromView()\n\t{\n\t\tsuper.marshalFromView();\n\t\tthis._writeSelectionToAddress();\n\t}\n\n\t// --- Public API ---\n\n\t/**\n\t * Change the orientation and re-render.\n\t *\n\t * @param {string} pOrientation - \"vertical\" or \"horizontal\"\n\t */\n\tsetOrientation(pOrientation)\n\t{\n\t\tif (pOrientation !== 'vertical' && pOrientation !== 'horizontal')\n\t\t{\n\t\t\tthis.log.warn(`PICT-Histogram invalid orientation: ${pOrientation}`);\n\t\t\treturn;\n\t\t}\n\t\tthis.options.Orientation = pOrientation;\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\t/**\n\t * Change the render mode and re-render.\n\t *\n\t * @param {string} pRenderMode - \"browser\", \"consoleui\", or \"cli\"\n\t */\n\tsetRenderMode(pRenderMode)\n\t{\n\t\tthis.options.RenderMode = pRenderMode;\n\t\tthis._renderer = this._resolveRenderer();\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\t/**\n\t * Convenience: get the text representation (useful for CLI/consoleui).\n\t *\n\t * @returns {string}\n\t */\n\ttoText()\n\t{\n\t\tif (this.options.Orientation === 'vertical')\n\t\t{\n\t\t\treturn libRendererConsoleUI.renderVertical(this);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn libRendererConsoleUI.renderHorizontal(this);\n\t\t}\n\t}\n}\n\nmodule.exports = PictSectionHistogram;\n\nmodule.exports.default_configuration = _DefaultConfiguration;\nmodule.exports.renderers = {\n\tbrowser: libRendererBrowser,\n\tconsoleui: libRendererConsoleUI,\n\tcli: libRendererCLI\n};\n","/**\n * Browser renderer for pict-section-histogram.\n *\n * Renders the histogram as HTML/CSS elements using the Pict ContentAssignment\n * pipeline. Also wires up interactive selection (click, drag-slider) via\n * DOM event listeners.\n *\n * @module Pict-Histogram-Renderer-Browser\n */\n\n/**\n * Build the HTML string for a single bar group (bar + optional labels).\n *\n * @param {object} pBin - The bin data { Label, Value, ... }\n * @param {number} pIndex - Index of the bin\n * @param {number} pBarSize - Computed bar size in pixels\n * @param {object} pOptions - View options\n * @param {boolean} pIsSelected - Whether this bin is selected\n * @param {boolean} pInRange - Whether this bin is inside the range selection\n * @param {number} pLabelWidth - Fixed label width in pixels (horizontal mode)\n * @returns {string} HTML fragment\n */\nfunction buildBarGroupHTML(pBin, pIndex, pBarSize, pOptions, pIsSelected, pInRange, pLabelWidth)\n{\n\tlet tmpLabel = pBin[pOptions.LabelProperty] || '';\n\tlet tmpValue = pBin[pOptions.ValueProperty] || 0;\n\tlet tmpVertical = (pOptions.Orientation === 'vertical');\n\tlet tmpBarColor = pIsSelected ? pOptions.SelectedBarColor\n\t\t: pInRange ? pOptions.SelectionRangeColor\n\t\t: pOptions.BarColor;\n\n\tlet tmpSelectableClass = pOptions.Selectable ? ' pict-histogram-selectable' : '';\n\tlet tmpSelectedClass = pIsSelected ? ' pict-histogram-selected' : '';\n\tlet tmpInRangeClass = pInRange ? ' pict-histogram-in-range' : '';\n\n\tlet tmpFillMode = pOptions.FillContainer;\n\n\tlet tmpBarStyle = '';\n\tif (tmpVertical)\n\t{\n\t\tif (tmpFillMode)\n\t\t{\n\t\t\ttmpBarStyle = `height:${pBarSize}px;background-color:${tmpBarColor};`;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpBarStyle = `height:${pBarSize}px;width:${pOptions.BarThickness}px;background-color:${tmpBarColor};`;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (tmpFillMode)\n\t\t{\n\t\t\ttmpBarStyle = `width:${pBarSize}px;background-color:${tmpBarColor};`;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpBarStyle = `width:${pBarSize}px;height:${pOptions.BarThickness}px;background-color:${tmpBarColor};`;\n\t\t}\n\t}\n\n\tlet tmpGroupWidth = pOptions.BarThickness + pOptions.BarGap;\n\tlet tmpGroupStyle = '';\n\tif (tmpFillMode)\n\t{\n\t\t// No fixed dimensions — CSS flex:1 handles sizing\n\t\ttmpGroupStyle = '';\n\t}\n\telse if (tmpVertical)\n\t{\n\t\ttmpGroupStyle = `margin:0 ${pOptions.BarGap / 2}px;width:${tmpGroupWidth}px;`;\n\t}\n\telse\n\t{\n\t\ttmpGroupStyle = `margin:${pOptions.BarGap / 2}px 0;`;\n\t}\n\n\tlet tmpHTML = `<div class=\"pict-histogram-bar-group\" style=\"${tmpGroupStyle}\" data-histogram-index=\"${pIndex}\">`;\n\n\tif (tmpVertical)\n\t{\n\t\t// Value label above bar (skipped in fill mode — values don't fit in narrow columns)\n\t\tif (pOptions.ShowValues && !tmpFillMode)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-value-label\" style=\"width:${tmpGroupWidth}px;\">${tmpValue}</div>`;\n\t\t}\n\t\t// Bar\n\t\ttmpHTML += `<div class=\"pict-histogram-bar${tmpSelectableClass}${tmpSelectedClass}${tmpInRangeClass}\" style=\"${tmpBarStyle}\" data-histogram-index=\"${pIndex}\"></div>`;\n\t\t// Bin label below bar (skipped in fill mode — labels rendered in a separate row)\n\t\tif (pOptions.ShowLabels && !tmpFillMode)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-bin-label\" style=\"width:${tmpGroupWidth}px;\">${tmpLabel}</div>`;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Bin label to the left (fixed width so bars align)\n\t\tif (pOptions.ShowLabels)\n\t\t{\n\t\t\tlet tmpLabelStyle = pLabelWidth ? `width:${pLabelWidth}px;min-width:${pLabelWidth}px;` : '';\n\t\t\ttmpHTML += `<div class=\"pict-histogram-bin-label\" style=\"${tmpLabelStyle}\">${tmpLabel}</div>`;\n\t\t}\n\t\t// Bar\n\t\ttmpHTML += `<div class=\"pict-histogram-bar${tmpSelectableClass}${tmpSelectedClass}${tmpInRangeClass}\" style=\"${tmpBarStyle}\" data-histogram-index=\"${pIndex}\"></div>`;\n\t\t// Value label to the right\n\t\tif (pOptions.ShowValues)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-value-label\">${tmpValue}</div>`;\n\t\t}\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Build the HTML for the range-slider overlay (used in \"range\" selection mode).\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} HTML fragment\n */\nfunction buildRangeSliderHTML(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '';\n\t}\n\n\tlet tmpRangeStart = pView._selectionRangeStart;\n\tlet tmpRangeEnd = pView._selectionRangeEnd;\n\tlet tmpMax = tmpBins.length - 1;\n\n\t// Calculate percentage positions for the handles\n\tlet tmpStartPct = (tmpMax > 0) ? ((tmpRangeStart / tmpMax) * 100) : 0;\n\tlet tmpEndPct = (tmpMax > 0) ? ((tmpRangeEnd / tmpMax) * 100) : 100;\n\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\n\tlet tmpHTML = '<div class=\"pict-histogram-range-slider-container\">';\n\ttmpHTML += '<div class=\"pict-histogram-range-track\"></div>';\n\n\tif (tmpVertical)\n\t{\n\t\ttmpHTML += `<div class=\"pict-histogram-range-fill\" style=\"left:${tmpStartPct}%;right:${100 - tmpEndPct}%;\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-start\" tabindex=\"0\" style=\"left:${tmpStartPct}%;\" data-handle=\"start\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-end\" tabindex=\"0\" style=\"left:${tmpEndPct}%;\" data-handle=\"end\"></div>`;\n\t}\n\telse\n\t{\n\t\ttmpHTML += `<div class=\"pict-histogram-range-fill\" style=\"top:${tmpStartPct}%;bottom:${100 - tmpEndPct}%;\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-start\" tabindex=\"0\" style=\"top:${tmpStartPct}%;\" data-handle=\"start\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-end\" tabindex=\"0\" style=\"top:${tmpEndPct}%;\" data-handle=\"end\"></div>`;\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Build the label row for FillContainer vertical mode.\n *\n * Labels are rendered in a separate flex row below the axis line, with\n * automatic interval calculation to avoid overlap when there are many bins.\n *\n * @param {object} pView - The histogram view instance\n * @param {Array} pBins - The bin data array\n * @returns {string} HTML fragment\n */\nfunction buildFillLabelRow(pView, pBins)\n{\n\tif (!pBins || pBins.length === 0)\n\t{\n\t\treturn '';\n\t}\n\n\t// Determine label interval: explicit setting or auto-compute\n\tlet tmpLabelInterval = pView.options.LabelInterval || 0;\n\tif (tmpLabelInterval <= 0)\n\t{\n\t\t// Auto-compute: space labels approximately 80px apart\n\t\tlet tmpTargetElementSet = pView.services.ContentAssignment.getElement(pView.options.TargetElementAddress);\n\t\tlet tmpContainerWidth = 800;\n\t\tif (tmpTargetElementSet && tmpTargetElementSet.length > 0 && tmpTargetElementSet[0])\n\t\t{\n\t\t\ttmpContainerWidth = tmpTargetElementSet[0].clientWidth || 800;\n\t\t}\n\t\tif (pBins.length > 0)\n\t\t{\n\t\t\tlet tmpBarWidth = tmpContainerWidth / pBins.length;\n\t\t\ttmpLabelInterval = Math.max(1, Math.ceil(80 / tmpBarWidth));\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLabelInterval = 1;\n\t\t}\n\t}\n\n\tlet tmpHTML = '<div class=\"pict-histogram-label-row\">';\n\n\tfor (let i = 0; i < pBins.length; i++)\n\t{\n\t\tlet tmpIsLabeled = (i % tmpLabelInterval === 0);\n\t\tif (tmpIsLabeled)\n\t\t{\n\t\t\tlet tmpLabel = pBins[i][pView.options.LabelProperty] || '';\n\t\t\t// Span covers this label and the unlabeled bars until the next label\n\t\t\tlet tmpSpan = Math.min(tmpLabelInterval, pBins.length - i);\n\t\t\ttmpHTML += `<div class=\"pict-histogram-fill-label\" style=\"flex:${tmpSpan};\">${tmpLabel}</div>`;\n\t\t\ti += tmpSpan - 1;\n\t\t}\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Render the full histogram into the target element.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\tpView.services.ContentAssignment.assignContent(\n\t\t\tpView.options.TargetElementAddress,\n\t\t\t'<div class=\"pict-histogram-container\"><em>No histogram data</em></div>'\n\t\t);\n\t\treturn;\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][pView.options.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\tlet tmpOrientationClass = tmpVertical ? 'pict-histogram-vertical' : 'pict-histogram-horizontal';\n\tlet tmpFillClass = pView.options.FillContainer ? ' pict-histogram-fill' : '';\n\n\t// For horizontal mode (non-fill), measure the longest label so all labels share the same width\n\tlet tmpLabelWidth = 0;\n\tif (!tmpVertical && pView.options.ShowLabels && !pView.options.FillContainer)\n\t{\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][pView.options.LabelProperty] || '');\n\t\t\t// Approximate character width at 11px font: ~6.5px per character\n\t\t\tlet tmpEstWidth = tmpLabel.length * 6.5 + 8;\n\t\t\tif (tmpEstWidth > tmpLabelWidth)\n\t\t\t{\n\t\t\t\ttmpLabelWidth = tmpEstWidth;\n\t\t\t}\n\t\t}\n\t\ttmpLabelWidth = Math.max(tmpLabelWidth, 40);\n\t}\n\n\tlet tmpHTML = `<div class=\"pict-histogram-container ${tmpOrientationClass}${tmpFillClass}\">`;\n\ttmpHTML += `<div class=\"pict-histogram-chart ${tmpOrientationClass}${tmpFillClass}\">`;\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][pView.options.ValueProperty] || 0;\n\t\tlet tmpBarSize = Math.round((tmpVal / tmpMaxValue) * pView.options.MaxBarSize);\n\t\tif (tmpVal > 0 && tmpBarSize < 1)\n\t\t{\n\t\t\ttmpBarSize = 1;\n\t\t}\n\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\n\t\ttmpHTML += buildBarGroupHTML(tmpBins[i], i, tmpBarSize, pView.options, tmpIsSelected, tmpInRange, tmpLabelWidth);\n\t}\n\n\ttmpHTML += '</div>';\n\n\t// In FillContainer vertical mode, render axis line and label row separately\n\tif (pView.options.FillContainer && tmpVertical && pView.options.ShowLabels)\n\t{\n\t\ttmpHTML += '<div class=\"pict-histogram-axis-line\"></div>';\n\t\ttmpHTML += buildFillLabelRow(pView, tmpBins);\n\t}\n\n\t// Range slider for \"range\" selection mode\n\tif (pView.options.Selectable && pView.options.SelectionMode === 'range')\n\t{\n\t\ttmpHTML += buildRangeSliderHTML(pView);\n\t}\n\n\ttmpHTML += '</div>';\n\n\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpHTML);\n}\n\n/**\n * Wire up DOM event listeners for interactivity (click selection, range drag).\n *\n * @param {object} pView - The histogram view instance\n */\nfunction wireEvents(pView)\n{\n\tif (!pView.options.Selectable)\n\t{\n\t\treturn;\n\t}\n\n\tlet tmpTargetElementSet = pView.services.ContentAssignment.getElement(pView.options.TargetElementAddress);\n\tif (!tmpTargetElementSet || tmpTargetElementSet.length < 1)\n\t{\n\t\treturn;\n\t}\n\tlet tmpContainer = tmpTargetElementSet[0];\n\tif (!tmpContainer)\n\t{\n\t\treturn;\n\t}\n\n\t// --- Bar click selection (single / multiple modes) ---\n\tif (pView.options.SelectionMode === 'single' || pView.options.SelectionMode === 'multiple')\n\t{\n\t\tlet tmpBars = tmpContainer.querySelectorAll('.pict-histogram-bar[data-histogram-index]');\n\t\tfor (let i = 0; i < tmpBars.length; i++)\n\t\t{\n\t\t\ttmpBars[i].addEventListener('click', (pEvent) =>\n\t\t\t{\n\t\t\t\tlet tmpIndex = parseInt(pEvent.currentTarget.getAttribute('data-histogram-index'), 10);\n\t\t\t\tif (isNaN(tmpIndex))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpView.handleBarClick(tmpIndex);\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Range slider drag ---\n\tif (pView.options.SelectionMode === 'range')\n\t{\n\t\t// Also allow clicking bars to move nearest handle\n\t\tlet tmpBars = tmpContainer.querySelectorAll('.pict-histogram-bar[data-histogram-index]');\n\t\tfor (let i = 0; i < tmpBars.length; i++)\n\t\t{\n\t\t\ttmpBars[i].addEventListener('click', (pEvent) =>\n\t\t\t{\n\t\t\t\tlet tmpIndex = parseInt(pEvent.currentTarget.getAttribute('data-histogram-index'), 10);\n\t\t\t\tif (isNaN(tmpIndex))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpView.handleRangeBarClick(tmpIndex);\n\t\t\t});\n\t\t}\n\n\t\tlet tmpHandles = tmpContainer.querySelectorAll('.pict-histogram-range-handle');\n\t\tfor (let i = 0; i < tmpHandles.length; i++)\n\t\t{\n\t\t\twireRangeHandle(pView, tmpHandles[i], tmpContainer);\n\t\t}\n\t}\n}\n\n/**\n * Wire drag behavior on a single range handle element.\n *\n * @param {object} pView - The histogram view instance\n * @param {Element} pHandle - The handle DOM element\n * @param {Element} pContainer - The histogram container element\n */\nfunction wireRangeHandle(pView, pHandle, pContainer)\n{\n\tlet tmpHandleType = pHandle.getAttribute('data-handle'); // \"start\" or \"end\"\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\n\tlet tmpDragging = false;\n\n\tfunction getSliderBounds()\n\t{\n\t\t// Re-query from pContainer every time because renderHistogram() replaces\n\t\t// the inner HTML, detaching any previously-captured slider element.\n\t\tlet tmpSlider = pContainer.querySelector('.pict-histogram-range-slider-container');\n\t\tif (!tmpSlider)\n\t\t{\n\t\t\treturn { start: 0, size: 1 };\n\t\t}\n\t\tlet tmpRect = tmpSlider.getBoundingClientRect();\n\t\tif (tmpVertical)\n\t\t{\n\t\t\treturn { start: tmpRect.left, size: tmpRect.width || 1 };\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn { start: tmpRect.top, size: tmpRect.height || 1 };\n\t\t}\n\t}\n\n\tfunction onPointerMove(pEvent)\n\t{\n\t\tif (!tmpDragging)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBins = pView.getBins();\n\t\tif (!tmpBins || tmpBins.length === 0)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBounds = getSliderBounds();\n\t\tlet tmpPos = tmpVertical ? pEvent.clientX : pEvent.clientY;\n\t\tlet tmpPct = (tmpPos - tmpBounds.start) / tmpBounds.size;\n\t\ttmpPct = Math.max(0, Math.min(1, tmpPct));\n\n\t\tlet tmpIndex = Math.round(tmpPct * (tmpBins.length - 1));\n\n\t\tif (tmpHandleType === 'start')\n\t\t{\n\t\t\tif (tmpIndex > pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpIndex = pView._selectionRangeEnd;\n\t\t\t}\n\t\t\tpView._selectionRangeStart = tmpIndex;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (tmpIndex < pView._selectionRangeStart)\n\t\t\t{\n\t\t\t\ttmpIndex = pView._selectionRangeStart;\n\t\t\t}\n\t\t\tpView._selectionRangeEnd = tmpIndex;\n\t\t}\n\n\t\tpView._syncSelectionFromRange();\n\t\tpView.renderHistogram();\n\t}\n\n\tfunction onPointerUp()\n\t{\n\t\tif (!tmpDragging)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\ttmpDragging = false;\n\t\tif (typeof (document) !== 'undefined')\n\t\t{\n\t\t\tdocument.removeEventListener('mousemove', onPointerMove);\n\t\t\tdocument.removeEventListener('mouseup', onPointerUp);\n\t\t}\n\t}\n\n\tpHandle.addEventListener('mousedown', (pEvent) =>\n\t{\n\t\tpEvent.preventDefault();\n\t\ttmpDragging = true;\n\t\tif (typeof (document) !== 'undefined')\n\t\t{\n\t\t\tdocument.addEventListener('mousemove', onPointerMove);\n\t\t\tdocument.addEventListener('mouseup', onPointerUp);\n\t\t}\n\t});\n}\n\nmodule.exports = { render, wireEvents };\n","/**\n * CLI renderer for pict-section-histogram.\n *\n * Renders the histogram as ANSI-colored text written directly to stdout\n * (or through the Pict ContentAssignment pipeline if available).\n *\n * This mode is intended for command-line tools that print histogram output\n * without a full terminal UI framework.\n *\n * @module Pict-Histogram-Renderer-CLI\n */\n\n// ANSI color codes (basic 16-color)\nconst ANSI_COLORS = {\n\t'black': '\\x1b[30m',\n\t'red': '\\x1b[31m',\n\t'green': '\\x1b[32m',\n\t'yellow': '\\x1b[33m',\n\t'blue': '\\x1b[34m',\n\t'magenta': '\\x1b[35m',\n\t'cyan': '\\x1b[36m',\n\t'white': '\\x1b[37m',\n\t'reset': '\\x1b[0m',\n\t'bold': '\\x1b[1m',\n\t'dim': '\\x1b[2m'\n};\n\n/**\n * Map a CSS-ish color string to the nearest ANSI color.\n *\n * @param {string} pColor - A color string (name or hex)\n * @returns {string} ANSI escape code\n */\nfunction colorToAnsi(pColor)\n{\n\tif (!pColor)\n\t{\n\t\treturn ANSI_COLORS.blue;\n\t}\n\n\tlet tmpLower = pColor.toLowerCase();\n\n\t// Direct name match\n\tif (ANSI_COLORS[tmpLower])\n\t{\n\t\treturn ANSI_COLORS[tmpLower];\n\t}\n\n\t// Simple hex-to-nearest mapping\n\tif (tmpLower.charAt(0) === '#' && tmpLower.length >= 7)\n\t{\n\t\tlet tmpR = parseInt(tmpLower.substring(1, 3), 16);\n\t\tlet tmpG = parseInt(tmpLower.substring(3, 5), 16);\n\t\tlet tmpB = parseInt(tmpLower.substring(5, 7), 16);\n\n\t\t// Pick nearest basic color\n\t\tif (tmpG > tmpR && tmpG > tmpB)\n\t\t{\n\t\t\treturn ANSI_COLORS.green;\n\t\t}\n\t\tif (tmpR > tmpG && tmpR > tmpB)\n\t\t{\n\t\t\treturn ANSI_COLORS.red;\n\t\t}\n\t\tif (tmpB > tmpR && tmpB > tmpG)\n\t\t{\n\t\t\treturn ANSI_COLORS.blue;\n\t\t}\n\t\tif (tmpR > 200 && tmpG > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.yellow;\n\t\t}\n\t\tif (tmpR > 200 && tmpB > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.magenta;\n\t\t}\n\t\tif (tmpG > 200 && tmpB > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.cyan;\n\t\t}\n\t}\n\n\treturn ANSI_COLORS.blue;\n}\n\n/**\n * Render a vertical CLI histogram.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The ANSI text output\n */\nfunction renderVertical(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpHeight = tmpOptions.TextHeight || 15;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\tlet tmpBarColor = colorToAnsi(tmpOptions.BarColor);\n\tlet tmpSelectedColor = colorToAnsi(tmpOptions.SelectedBarColor);\n\tlet tmpRangeColor = colorToAnsi(tmpOptions.SelectionRangeColor);\n\tlet tmpReset = ANSI_COLORS.reset;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)\\n';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpValueAxisWidth = String(tmpMaxValue).length + 1;\n\tlet tmpLines = [];\n\n\tfor (let tmpRow = tmpHeight; tmpRow >= 1; tmpRow--)\n\t{\n\t\tlet tmpLine = '';\n\n\t\t// Axis labels\n\t\tif (tmpRow === tmpHeight)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft(String(tmpMaxValue), tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse if (tmpRow === 1)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft('0', tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse if (tmpRow === Math.ceil(tmpHeight / 2))\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft(String(Math.round(tmpMaxValue / 2)), tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft('', tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\t\tlet tmpBarHeight = (tmpVal / tmpMaxValue) * tmpHeight;\n\t\t\tlet tmpFullRows = Math.floor(tmpBarHeight);\n\t\t\tlet tmpFraction = tmpBarHeight - tmpFullRows;\n\n\t\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\t\tlet tmpColor = tmpIsSelected ? tmpSelectedColor : (tmpInRange ? tmpRangeColor : tmpBarColor);\n\n\t\t\tlet tmpChar = ' ';\n\t\t\tif (tmpRow <= tmpFullRows)\n\t\t\t{\n\t\t\t\ttmpChar = tmpBarChar;\n\t\t\t}\n\t\t\telse if (tmpRow === tmpFullRows + 1 && tmpFraction > 0)\n\t\t\t{\n\t\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\t\ttmpChar = tmpPartials[tmpPartialIndex];\n\t\t\t}\n\n\t\t\tif (tmpChar !== ' ')\n\t\t\t{\n\t\t\t\ttmpLine += ' ' + tmpColor + tmpChar + tmpChar + tmpChar + tmpReset;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpLine += ' ';\n\t\t\t}\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Bottom axis\n\tlet tmpAxisLine = ANSI_COLORS.dim + padLeft('', tmpValueAxisWidth) + '+';\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\ttmpAxisLine += '----';\n\t}\n\ttmpAxisLine += tmpReset;\n\ttmpLines.push(tmpAxisLine);\n\n\t// Labels\n\tif (tmpOptions.ShowLabels)\n\t{\n\t\tlet tmpLabelLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\t\ttmpLabelLine += padCenter(tmpLabel.substring(0, 4), 4);\n\t\t}\n\t\ttmpLines.push(tmpLabelLine);\n\t}\n\n\t// Range selection info\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpStart = pView._selectionRangeStart;\n\t\tlet tmpEnd = pView._selectionRangeEnd;\n\t\tlet tmpStartLabel = tmpBins[tmpStart] ? tmpBins[tmpStart][tmpOptions.LabelProperty] : tmpStart;\n\t\tlet tmpEndLabel = tmpBins[tmpEnd] ? tmpBins[tmpEnd][tmpOptions.LabelProperty] : tmpEnd;\n\t\ttmpLines.push('');\n\t\ttmpLines.push(ANSI_COLORS.bold + ' Selection: ' + tmpStartLabel + ' - ' + tmpEndLabel + tmpReset);\n\t}\n\n\treturn tmpLines.join('\\n') + '\\n';\n}\n\n/**\n * Render a horizontal CLI histogram.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The ANSI text output\n */\nfunction renderHorizontal(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpWidth = tmpOptions.TextWidth || 60;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpBarColor = colorToAnsi(tmpOptions.BarColor);\n\tlet tmpSelectedColor = colorToAnsi(tmpOptions.SelectedBarColor);\n\tlet tmpRangeColor = colorToAnsi(tmpOptions.SelectionRangeColor);\n\tlet tmpReset = ANSI_COLORS.reset;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)\\n';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tlet tmpMaxLabelLen = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tif (tmpLabel.length > tmpMaxLabelLen)\n\t\t{\n\t\t\ttmpMaxLabelLen = tmpLabel.length;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpLabelWidth = Math.min(tmpMaxLabelLen, 12);\n\tlet tmpValueWidth = String(tmpMaxValue).length;\n\tlet tmpBarWidth = tmpWidth - tmpLabelWidth - tmpValueWidth - 4;\n\tif (tmpBarWidth < 10)\n\t{\n\t\ttmpBarWidth = 10;\n\t}\n\n\tlet tmpLines = [];\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tlet tmpBarLen = Math.round((tmpVal / tmpMaxValue) * tmpBarWidth);\n\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\tlet tmpColor = tmpIsSelected ? tmpSelectedColor : (tmpInRange ? tmpRangeColor : tmpBarColor);\n\n\t\tlet tmpBar = '';\n\t\tfor (let j = 0; j < tmpBarLen; j++)\n\t\t{\n\t\t\ttmpBar += tmpBarChar;\n\t\t}\n\n\t\tlet tmpLine = ANSI_COLORS.dim + padRight(tmpLabel.substring(0, tmpLabelWidth), tmpLabelWidth) + ' |' + tmpReset;\n\t\ttmpLine += tmpColor + tmpBar + tmpReset;\n\t\ttmpLine += ' ' + tmpVal;\n\n\t\tif (tmpIsSelected)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.bold + ' *' + tmpReset;\n\t\t}\n\t\telse if (tmpInRange)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + ' ~' + tmpReset;\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Range info\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpStart = pView._selectionRangeStart;\n\t\tlet tmpEnd = pView._selectionRangeEnd;\n\t\tlet tmpStartLabel = tmpBins[tmpStart] ? tmpBins[tmpStart][tmpOptions.LabelProperty] : tmpStart;\n\t\tlet tmpEndLabel = tmpBins[tmpEnd] ? tmpBins[tmpEnd][tmpOptions.LabelProperty] : tmpEnd;\n\t\ttmpLines.push('');\n\t\ttmpLines.push(ANSI_COLORS.bold + ' Selection: ' + tmpStartLabel + ' - ' + tmpEndLabel + tmpReset);\n\t}\n\n\treturn tmpLines.join('\\n') + '\\n';\n}\n\n/**\n * Render in CLI mode. Writes to ContentAssignment if available, otherwise\n * falls back to process.stdout.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpText;\n\tif (pView.options.Orientation === 'vertical')\n\t{\n\t\ttmpText = renderVertical(pView);\n\t}\n\telse\n\t{\n\t\ttmpText = renderHorizontal(pView);\n\t}\n\n\t// Try ContentAssignment first (might be mocked in tests or bridged)\n\tif (pView.services && pView.services.ContentAssignment)\n\t{\n\t\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpText);\n\t}\n\telse if (typeof (process) !== 'undefined' && process.stdout)\n\t{\n\t\tprocess.stdout.write(tmpText);\n\t}\n}\n\n// No interactive events in CLI mode\nfunction wireEvents()\n{\n\t// No-op for CLI\n}\n\n// --- Utility ---\n\nfunction padLeft(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = ' ' + tmpStr;\n\t}\n\treturn tmpStr;\n}\n\nfunction padRight(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = tmpStr + ' ';\n\t}\n\treturn tmpStr;\n}\n\nfunction padCenter(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = (tmpStr.length % 2 === 0) ? (tmpStr + ' ') : (' ' + tmpStr);\n\t}\n\treturn tmpStr;\n}\n\nmodule.exports = { render, wireEvents, renderVertical, renderHorizontal, colorToAnsi, ANSI_COLORS };\n","/**\n * Console UI (blessed) renderer for pict-section-histogram.\n *\n * Renders the histogram as text art through the Pict ContentAssignment\n * pipeline, suitable for blessed/ncurses terminal UI widgets.\n *\n * The output is assigned via ContentAssignment so the pict-terminalui\n * bridge (customAssignFunction) can project it into blessed boxes.\n *\n * @module Pict-Histogram-Renderer-ConsoleUI\n */\n\n/**\n * Build a vertical text histogram.\n *\n * Each column is one bar. Rows go from top (max value) to bottom (0).\n * Uses block characters for fractional rows.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The rendered text block\n */\nfunction renderVertical(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpHeight = tmpOptions.TextHeight || 15;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\tlet tmpEmptyChar = tmpOptions.EmptyCharacter;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\t// Determine label width for the value axis\n\tlet tmpValueAxisWidth = String(tmpMaxValue).length + 1;\n\n\t// Build the grid top-down\n\tlet tmpLines = [];\n\n\tfor (let tmpRow = tmpHeight; tmpRow >= 1; tmpRow--)\n\t{\n\t\tlet tmpLine = '';\n\n\t\t// Value axis label (only on a few rows)\n\t\tif (tmpRow === tmpHeight)\n\t\t{\n\t\t\ttmpLine += padLeft(String(tmpMaxValue), tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse if (tmpRow === 1)\n\t\t{\n\t\t\ttmpLine += padLeft('0', tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse if (tmpRow === Math.ceil(tmpHeight / 2))\n\t\t{\n\t\t\ttmpLine += padLeft(String(Math.round(tmpMaxValue / 2)), tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLine += padLeft('', tmpValueAxisWidth) + '|';\n\t\t}\n\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\t\tlet tmpBarHeight = (tmpVal / tmpMaxValue) * tmpHeight;\n\t\t\tlet tmpFullRows = Math.floor(tmpBarHeight);\n\t\t\tlet tmpFraction = tmpBarHeight - tmpFullRows;\n\n\t\t\tlet tmpChar = tmpEmptyChar;\n\t\t\tif (tmpRow <= tmpFullRows)\n\t\t\t{\n\t\t\t\ttmpChar = tmpBarChar;\n\t\t\t}\n\t\t\telse if (tmpRow === tmpFullRows + 1 && tmpFraction > 0)\n\t\t\t{\n\t\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\t\ttmpChar = tmpPartials[tmpPartialIndex];\n\t\t\t}\n\n\t\t\t// Mark selected bins\n\t\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\n\t\t\tif (tmpIsSelected && tmpChar !== tmpEmptyChar)\n\t\t\t{\n\t\t\t\ttmpChar = '*';\n\t\t\t}\n\t\t\telse if (tmpInRange && tmpChar !== tmpEmptyChar)\n\t\t\t{\n\t\t\t\ttmpChar = '#';\n\t\t\t}\n\n\t\t\t// Each bar is 3 chars wide with 1 char gap\n\t\t\ttmpLine += ' ' + tmpChar + tmpChar + tmpChar;\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Bottom axis\n\tlet tmpAxisLine = padLeft('', tmpValueAxisWidth) + '+';\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\ttmpAxisLine += '----';\n\t}\n\ttmpLines.push(tmpAxisLine);\n\n\t// Labels row\n\tif (tmpOptions.ShowLabels)\n\t{\n\t\tlet tmpLabelLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\t\ttmpLabelLine += padCenter(tmpLabel.substring(0, 4), 4);\n\t\t}\n\t\ttmpLines.push(tmpLabelLine);\n\t}\n\n\t// Selection range indicator\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpRangeLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tif (i === pView._selectionRangeStart)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' [ ';\n\t\t\t}\n\t\t\telse if (i === pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' ] ';\n\t\t\t}\n\t\t\telse if (i > pView._selectionRangeStart && i < pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' - ';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' ';\n\t\t\t}\n\t\t}\n\t\ttmpLines.push(tmpRangeLine);\n\t}\n\n\treturn tmpLines.join('\\n');\n}\n\n/**\n * Build a horizontal text histogram.\n *\n * Each row is one bar growing rightward.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The rendered text block\n */\nfunction renderHorizontal(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpWidth = tmpOptions.TextWidth || 60;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tlet tmpMaxLabelLen = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tif (tmpLabel.length > tmpMaxLabelLen)\n\t\t{\n\t\t\ttmpMaxLabelLen = tmpLabel.length;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpLabelWidth = Math.min(tmpMaxLabelLen, 12);\n\tlet tmpBarWidth = tmpWidth - tmpLabelWidth - 2; // space for \" |\"\n\tif (tmpBarWidth < 10)\n\t{\n\t\ttmpBarWidth = 10;\n\t}\n\n\tlet tmpLines = [];\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tlet tmpBarLen = (tmpVal / tmpMaxValue) * tmpBarWidth;\n\t\tlet tmpFullChars = Math.floor(tmpBarLen);\n\t\tlet tmpFraction = tmpBarLen - tmpFullChars;\n\n\t\tlet tmpBar = '';\n\t\tfor (let j = 0; j < tmpFullChars; j++)\n\t\t{\n\t\t\ttmpBar += tmpBarChar;\n\t\t}\n\t\tif (tmpFraction > 0 && tmpFullChars < tmpBarWidth)\n\t\t{\n\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\ttmpBar += tmpPartials[tmpPartialIndex];\n\t\t}\n\n\t\t// Mark selected\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\tlet tmpMarker = tmpIsSelected ? '*' : (tmpInRange ? '~' : '');\n\n\t\tlet tmpValueStr = tmpOptions.ShowValues ? (' ' + tmpVal) : '';\n\t\tlet tmpLine = padRight(tmpLabel.substring(0, tmpLabelWidth), tmpLabelWidth) + ' |' + tmpBar + tmpValueStr + tmpMarker;\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Range indicator for range selection\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\ttmpLines.push('');\n\t\ttmpLines.push(padRight('', tmpLabelWidth) + ' Range: [' + pView._selectionRangeStart + ' - ' + pView._selectionRangeEnd + ']');\n\t}\n\n\treturn tmpLines.join('\\n');\n}\n\n/**\n * Render via ContentAssignment for consoleui mode.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpText;\n\tif (pView.options.Orientation === 'vertical')\n\t{\n\t\ttmpText = renderVertical(pView);\n\t}\n\telse\n\t{\n\t\ttmpText = renderHorizontal(pView);\n\t}\n\n\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpText);\n}\n\n// No interactive events for consoleui — input is handled by the blessed widget layer\nfunction wireEvents()\n{\n\t// No-op for consoleui\n}\n\n// --- Utility ---\n\nfunction padLeft(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = ' ' + tmpStr;\n\t}\n\treturn tmpStr;\n}\n\nfunction padRight(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = tmpStr + ' ';\n\t}\n\treturn tmpStr;\n}\n\nfunction padCenter(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = (tmpStr.length % 2 === 0) ? (tmpStr + ' ') : (' ' + tmpStr);\n\t}\n\treturn tmpStr;\n}\n\nmodule.exports = { render, wireEvents, renderVertical, renderHorizontal };\n","module.exports={\n \"name\": \"pict-view\",\n \"version\": \"1.0.67\",\n \"description\": \"Pict View Base Class\",\n \"main\": \"source/Pict-View.js\",\n \"scripts\": {\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"start\": \"node source/Pict-View.js\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-view-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-view-dev -p 30001:8080 -p 38086:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-view\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-view-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-view-dev /bin/bash\",\n \"types\": \"tsc -p .\",\n \"lint\": \"eslint source/**\"\n },\n \"types\": \"types/source/Pict-View.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-view.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-view/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-view#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.1\",\n \"browser-env\": \"^3.3.0\",\n \"eslint\": \"^9.39.1\",\n \"pict\": \"^1.0.348\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"dependencies\": {\n \"fable\": \"^3.1.63\",\n \"fable-serviceproviderbase\": \"^3.0.19\"\n }\n}\n","\nconst libFableServiceBase = require('fable-serviceproviderbase');\n\nconst libPackage = require('../package.json');\n\nconst defaultPictViewSettings = (\n\t{\n\t\tDefaultRenderable: false,\n\t\tDefaultDestinationAddress: false,\n\t\tDefaultTemplateRecordAddress: false,\n\n\t\tViewIdentifier: false,\n\n\t\t// If this is set to true, when the App initializes this will.\n\t\t// After the App initializes, initialize will be called as soon as it's added.\n\t\tAutoInitialize: true,\n\t\tAutoInitializeOrdinal: 0,\n\n\t\t// If this is set to true, when the App autorenders (on load) this will.\n\t\t// After the App initializes, render will be called as soon as it's added.\n\t\tAutoRender: true,\n\t\tAutoRenderOrdinal: 0,\n\n\t\tAutoSolveWithApp: true,\n\t\tAutoSolveOrdinal: 0,\n\n\t\tCSSHash: false,\n\t\tCSS: false,\n\t\tCSSProvider: false,\n\t\tCSSPriority: 500,\n\n\t\tTemplates: [],\n\n\t\tDefaultTemplates: [],\n\n\t\tRenderables: [],\n\n\t\tManifests: {}\n\t});\n\n/** @typedef {(error?: Error) => void} ErrorCallback */\n/** @typedef {number | boolean} PictTimestamp */\n\n/**\n * @typedef {'replace' | 'append' | 'prepend' | 'append_once' | 'virtual-assignment'} RenderMethod\n */\n/**\n * @typedef {Object} Renderable\n *\n * @property {string} RenderableHash - A unique hash for the renderable.\n * @property {string} TemplateHash - The hash of the template to use for rendering this renderable.\n * @property {string} [DefaultTemplateRecordAddress] - The default address for resolving the data record for this renderable.\n * @property {string} [ContentDestinationAddress] - The default address (DOM CSS selector) for rendering the content of this renderable.\n * @property {RenderMethod} [RenderMethod=replace] - The method to use when projecting the renderable to the DOM ('replace', 'append', 'prepend', 'append_once', 'virtual-assignment').\n * @property {string} [TestAddress] - The address to use for testing the renderable.\n * @property {string} [TransactionHash] - The transaction hash for the root renderable.\n * @property {string} [RootRenderableViewHash] - The hash of the root renderable.\n * @property {string} [Content] - The rendered content for this renderable, if applicable.\n */\n\n/**\n * Represents a view in the Pict ecosystem.\n */\nclass PictView extends libFableServiceBase\n{\n\t/**\n\t * @param {any} pFable - The Fable object that this service is attached to.\n\t * @param {any} [pOptions] - (optional) The options for this service.\n\t * @param {string} [pServiceHash] - (optional) The hash of the service.\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t// Intersect default options, parent constructor, service information\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictViewSettings)), pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\t\t//FIXME: add types to fable and ancillaries\n\t\t/** @type {any} */\n\t\tthis.fable;\n\t\t/** @type {any} */\n\t\tthis.options;\n\t\t/** @type {String} */\n\t\tthis.UUID;\n\t\t/** @type {String} */\n\t\tthis.Hash;\n\t\t/** @type {any} */\n\t\tthis.log;\n\n\t\tconst tmpHashIsUUID = this.Hash === this.UUID;\n\t\t//NOTE: since many places are using the view UUID as the HTML element ID, we prefix it to avoid starting with a number\n\t\tthis.UUID = `V-${this.UUID}`;\n\t\tif (tmpHashIsUUID)\n\t\t{\n\t\t\tthis.Hash = this.UUID;\n\t\t}\n\n\t\tif (!this.options.ViewIdentifier)\n\t\t{\n\t\t\tthis.options.ViewIdentifier = `AutoViewID-${this.fable.getUUID()}`;\n\t\t}\n\t\tthis.serviceType = 'PictView';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\t\t// Convenience and consistency naming\n\t\t/** @type {import('pict') & { log: any, instantiateServiceProviderWithoutRegistration: (hash: String) => any, instantiateServiceProviderIfNotExists: (hash: string) => any, TransactionTracking: import('pict/types/source/services/Fable-Service-TransactionTracking') }} */\n\t\tthis.pict = this.fable;\n\t\t// Wire in the essential Pict application state\n\t\tthis.AppData = this.pict.AppData;\n\t\tthis.Bundle = this.pict.Bundle;\n\n\t\t/** @type {PictTimestamp} */\n\t\tthis.initializeTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastSolvedTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastRenderedTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastMarshalFromViewTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastMarshalToViewTimestamp = false;\n\n\t\tthis.pict.instantiateServiceProviderIfNotExists('TransactionTracking');\n\n\t\t// Load all templates from the array in the options\n\t\t// Templates are in the form of {Hash:'Some-Template-Hash',Template:'Template content',Source:'TemplateSource'}\n\t\tfor (let i = 0; i < this.options.Templates.length; i++)\n\t\t{\n\t\t\tlet tmpTemplate = this.options.Templates[i];\n\n\t\t\tif (!('Hash' in tmpTemplate) || !('Template' in tmpTemplate))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Template ${i} in the options array.`, tmpTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpTemplate.Source = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addTemplate(tmpTemplate.Hash, tmpTemplate.Template, tmpTemplate.Source);\n\t\t\t}\n\t\t}\n\n\t\t// Load all default templates from the array in the options\n\t\t// Templates are in the form of {Prefix:'',Postfix:'-List-Row',Template:'Template content',Source:'TemplateSourceString'}\n\t\tfor (let i = 0; i < this.options.DefaultTemplates.length; i++)\n\t\t{\n\t\t\tlet tmpDefaultTemplate = this.options.DefaultTemplates[i];\n\n\t\t\tif (!('Postfix' in tmpDefaultTemplate) || !('Template' in tmpDefaultTemplate))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Default Template ${i} in the options array.`, tmpDefaultTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpDefaultTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpDefaultTemplate.Source = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix, tmpDefaultTemplate.Postfix, tmpDefaultTemplate.Template, tmpDefaultTemplate.Source);\n\t\t\t}\n\t\t}\n\n\t\t// Load the CSS if it's available\n\t\tif (this.options.CSS)\n\t\t{\n\t\t\tlet tmpCSSHash = this.options.CSSHash ? this.options.CSSHash : `View-${this.options.ViewIdentifier}`;\n\t\t\tlet tmpCSSProvider = this.options.CSSProvider ? this.options.CSSProvider : tmpCSSHash;\n\t\t\tthis.pict.CSSMap.addCSS(tmpCSSHash, this.options.CSS, tmpCSSProvider, this.options.CSSPriority);\n\t\t}\n\n\t\t// Load all renderables\n\t\t// Renderables are launchable renderable instructions with templates\n\t\t// They look as such: {Identifier:'ContentEntry', TemplateHash:'Content-Entry-Section-Main', ContentDestinationAddress:'#ContentSection', RecordAddress:'AppData.Content.DefaultText', ManifestTransformation:'ManyfestHash', ManifestDestinationAddress:'AppData.Content.DataToTransformContent'}\n\t\t// The only parts that are necessary are Identifier and Template\n\t\t// A developer can then do render('ContentEntry') and it just kinda works. Or they can override the ContentDestinationAddress\n\t\t/** @type {Record<String, Renderable>} */\n\t\tthis.renderables = {};\n\t\tfor (let i = 0; i < this.options.Renderables.length; i++)\n\t\t{\n\t\t\t/** @type {Renderable} */\n\t\t\tlet tmpRenderable = this.options.Renderables[i];\n\t\t\tthis.addRenderable(tmpRenderable);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a renderable to the view.\n\t *\n\t * @param {string | Renderable} pRenderableHash - The hash of the renderable, or a renderable object.\n\t * @param {string} [pTemplateHash] - (optional) The hash of the template for the renderable.\n\t * @param {string} [pDefaultTemplateRecordAddress] - (optional) The default data address for the template.\n\t * @param {string} [pDefaultDestinationAddress] - (optional) The default destination address for the renderable.\n\t * @param {RenderMethod} [pRenderMethod=replace] - (optional) The method to use when rendering the renderable (ex. 'replace').\n\t */\n\taddRenderable(pRenderableHash, pTemplateHash, pDefaultTemplateRecordAddress, pDefaultDestinationAddress, pRenderMethod)\n\t{\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\n\t\tif (typeof(pRenderableHash) == 'object')\n\t\t{\n\t\t\t// The developer passed in the renderable as an object.\n\t\t\t// Use theirs instead!\n\t\t\ttmpRenderable = pRenderableHash;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/** @type {RenderMethod} */\n\t\t\tlet tmpRenderMethod = (typeof(pRenderMethod) !== 'string') ? pRenderMethod : 'replace';\n\t\t\ttmpRenderable = (\n\t\t\t\t{\n\t\t\t\t\tRenderableHash: pRenderableHash,\n\t\t\t\t\tTemplateHash: pTemplateHash,\n\t\t\t\t\tDefaultTemplateRecordAddress: pDefaultTemplateRecordAddress,\n\t\t\t\t\tContentDestinationAddress: pDefaultDestinationAddress,\n\t\t\t\t\tRenderMethod: tmpRenderMethod\n\t\t\t\t});\n\t\t}\n\n\t\tif ((typeof(tmpRenderable.RenderableHash) != 'string') || (typeof(tmpRenderable.TemplateHash) != 'string'))\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Renderable; RenderableHash or TemplateHash are invalid.`, tmpRenderable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} adding renderable [${tmpRenderable.RenderableHash}] pointed to template ${tmpRenderable.TemplateHash}.`);\n\t\t\t}\n\n\t\t\tthis.renderables[tmpRenderable.RenderableHash] = tmpRenderable;\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialization */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is initialized.\n\t */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is initialized.\n\t */\n\tonInitialize()\n\t{\n\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Performs view initialization.\n\t */\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\t\t\tthis.onInitialize();\n\t\t\tthis.onAfterInitialize();\n\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Performs view initialization (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initializeAsync:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.info(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} beginning initialization...`);\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t/** @param {Error} pError */\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialization failed: ${pError.message || pError}`, { stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.info(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fCallback();\n\t\t\t\t});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn fCallback();\n\t\t}\n\t}\n\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Render */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is rendered.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that will be rendered.\n\t */\n\tonBeforeRender(pRenderable)\n\t{\n\t\t// Overload this to mess with stuff before the content gets generated from the template\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is rendered (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that will be rendered.\n\t */\n\tonBeforeRenderAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onBeforeRender(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is projected into the DOM.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that will be projected.\n\t */\n\tonBeforeProject(pRenderable)\n\t{\n\t\t// Overload this to mess with stuff before the content gets generated from the template\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeProject:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is projected into the DOM (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that will be projected.\n\t */\n\tonBeforeProjectAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onBeforeProject(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Builds the render options for a renderable.\n\t *\n\t * For DRY purposes on the three flavors of render.\n\t *\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbuildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\tlet tmpRenderOptions = {Valid: true};\n\t\ttmpRenderOptions.RenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t\t\t\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ?\n\t\t\t\t\t\t\t\tthis.options.DefaultRenderable : false;\n\t\tif (!tmpRenderOptions.RenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not find a suitable RenderableHash ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\ttmpRenderOptions.Renderable = this.renderables[tmpRenderOptions.RenderableHash];\n\t\tif (!tmpRenderOptions.Renderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\ttmpRenderOptions.DestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t(typeof (tmpRenderOptions.Renderable.ContentDestinationAddress) === 'string') ? tmpRenderOptions.Renderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : false;\n\t\tif (!tmpRenderOptions.DestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address (param ${pRenderDestinationAddress}).`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRenderOptions.RecordAddress = 'Passed in as object';\n\t\t\ttmpRenderOptions.Record = pTemplateRecordAddress;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderOptions.RecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderOptions.Renderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderOptions.Renderable.DefaultTemplateRecordAddress :\n\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\t\t\ttmpRenderOptions.Record = (typeof (tmpRenderOptions.RecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRenderOptions.RecordAddress) : undefined;\n\t\t}\n\n\t\treturn tmpRenderOptions;\n\t}\n\n\t/**\n\t * Assigns the content to the destination address.\n\t *\n\t * For DRY purposes on the three flavors of render.\n\t *\n\t * @param {Renderable} pRenderable - The renderable to render.\n\t * @param {string} pRenderDestinationAddress - The address where the renderable will be rendered.\n\t * @param {string} pContent - The content to render.\n\t * @returns {boolean} - Returns true if the content was assigned successfully.\n\t * @memberof PictView\n\t */\n\tassignRenderContent(pRenderable, pRenderDestinationAddress, pContent)\n\t{\n\t\treturn this.pict.ContentAssignment.projectContent(pRenderable.RenderMethod, pRenderDestinationAddress, pContent, pRenderable.TestAddress);\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @return {boolean}\n\t */\n\trender(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable)\n\t{\n\t\treturn this.renderWithScope(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable);\n\t}\n\n\t/**\n\t * Render a renderable from this view, providing a specifici scope for the template.\n\t *\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @return {boolean}\n\t */\n\trenderWithScope(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable)\n\t{\n\t\tlet tmpRenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ? this.options.DefaultRenderable : false;\n\t\tif (!tmpRenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it is not a valid renderable.`);\n\t\t\treturn false;\n\t\t}\n\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\t\tif (tmpRenderableHash == '__Virtual')\n\t\t{\n\t\t\ttmpRenderable = {\n\t\t\t\tRenderableHash: '__Virtual',\n\t\t\t\tTemplateHash: this.renderables[this.options.DefaultRenderable].TemplateHash,\n\t\t\t\tContentDestinationAddress: (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null,\n\t\t\t\tRenderMethod: 'virtual-assignment',\n\t\t\t\tTransactionHash: pRootRenderable && pRootRenderable.TransactionHash,\n\t\t\t\tRootRenderableViewHash: pRootRenderable && pRootRenderable.RootRenderableViewHash,\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderable = Object.assign({}, this.renderables[tmpRenderableHash]);\n\t\t\ttmpRenderable.ContentDestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null;\n\t\t}\n\n\t\tif (!tmpRenderable.TransactionHash)\n\t\t{\n\t\t\ttmpRenderable.TransactionHash = `ViewRender-V-${this.options.ViewIdentifier}-R-${tmpRenderableHash}-U-${this.pict.getUUID()}`;\n\t\t\ttmpRenderable.RootRenderableViewHash = this.Hash;\n\t\t\tthis.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);\n\t\t}\n\n\t\tif (!tmpRenderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!tmpRenderable.ContentDestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tlet tmpRecordAddress;\n\t\tlet tmpRecord;\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRecord = pTemplateRecordAddress;\n\t\t\ttmpRecordAddress = 'Passed in as object';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderable.DefaultTemplateRecordAddress :\n\t\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\n\t\t\ttmpRecord = (typeof (tmpRecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRecordAddress) : undefined;\n\t\t}\n\n\t\t// Execute the developer-overridable pre-render behavior\n\t\tthis.onBeforeRender(tmpRenderable);\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] Renderable[${tmpRenderableHash}] Destination[${tmpRenderable.ContentDestinationAddress}] TemplateRecordAddress[${tmpRecordAddress}] render:`);\n\t\t}\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Beginning Render of Renderable[${tmpRenderableHash}] to Destination [${tmpRenderable.ContentDestinationAddress}]...`);\n\t\t}\n\t\t// Generate the content output from the template and data\n\t\ttmpRenderable.Content = this.pict.parseTemplateByHash(tmpRenderable.TemplateHash, tmpRecord, null, [this], pScope, { RootRenderable: typeof pRootRenderable === 'object' ? pRootRenderable : tmpRenderable });\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Assigning Renderable[${tmpRenderableHash}] content length ${tmpRenderable.Content.length} to Destination [${tmpRenderable.ContentDestinationAddress}] using render method [${tmpRenderable.RenderMethod}].`);\n\t\t}\n\n\t\tthis.onBeforeProject(tmpRenderable);\n\t\tthis.onProject(tmpRenderable);\n\n\t\tif (tmpRenderable.RenderMethod !== 'virtual-assignment')\n\t\t{\n\t\t\tthis.onAfterProject(tmpRenderable);\n\n\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\tthis.onAfterRender(tmpRenderable);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t *\n\t * @return {void}\n\t */\n\trenderAsync(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback)\n\t{\n\t\treturn this.renderWithScopeAsync(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback);\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t *\n\t * @return {void}\n\t */\n\trenderWithScopeAsync(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback)\n\t{\n\t\tlet tmpRenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ? this.options.DefaultRenderable : false;\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateRecordAddress) === 'function') ? pTemplateRecordAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\t(typeof(pRootRenderable) === 'function') ? pRootRenderable :\n\t\t\t\t\t\t\tnull;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (!tmpRenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not asynchronously render ${tmpRenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`);\n\t\t\treturn tmpCallback(new Error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not asynchronously render ${tmpRenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`));\n\t\t}\n\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\t\tif (tmpRenderableHash == '__Virtual')\n\t\t{\n\t\t\ttmpRenderable = {\n\t\t\t\tRenderableHash: '__Virtual',\n\t\t\t\tTemplateHash: this.renderables[this.options.DefaultRenderable].TemplateHash,\n\t\t\t\tContentDestinationAddress: (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress : (typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null,\n\t\t\t\tRenderMethod: 'virtual-assignment',\n\t\t\t\tTransactionHash: pRootRenderable && typeof pRootRenderable !== 'function' && pRootRenderable.TransactionHash,\n\t\t\t\tRootRenderableViewHash: pRootRenderable && typeof pRootRenderable !== 'function' && pRootRenderable.RootRenderableViewHash,\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderable = Object.assign({}, this.renderables[tmpRenderableHash]);\n\t\t\ttmpRenderable.ContentDestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null;\n\t\t}\n\n\t\tif (!tmpRenderable.TransactionHash)\n\t\t{\n\t\t\ttmpRenderable.TransactionHash = `ViewRender-V-${this.options.ViewIdentifier}-R-${tmpRenderableHash}-U-${this.pict.getUUID()}`;\n\t\t\ttmpRenderable.RootRenderableViewHash = this.Hash;\n\t\t\tthis.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);\n\t\t}\n\n\t\tif (!tmpRenderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\treturn tmpCallback(new Error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`));\n\t\t}\n\n\t\tif (!tmpRenderable.ContentDestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address.`);\n\t\t\treturn tmpCallback(new Error(`Could not render ${tmpRenderableHash}`));\n\t\t}\n\n\t\tlet tmpRecordAddress;\n\t\tlet tmpRecord;\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRecord = pTemplateRecordAddress;\n\t\t\ttmpRecordAddress = 'Passed in as object';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderable.DefaultTemplateRecordAddress :\n\t\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\n\t\t\ttmpRecord = (typeof (tmpRecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRecordAddress) : undefined;\n\t\t}\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] Renderable[${tmpRenderableHash}] Destination[${tmpRenderable.ContentDestinationAddress}] TemplateRecordAddress[${tmpRecordAddress}] renderAsync:`);\n\t\t}\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Beginning Asynchronous Render (callback-style)...`);\n\t\t}\n\n\t\tlet tmpAnticipate = this.fable.newAnticipate();\n\n\t\ttmpAnticipate.anticipate(\n\t\t\t(fOnBeforeRenderCallback) =>\n\t\t\t{\n\t\t\t\tthis.onBeforeRenderAsync(fOnBeforeRenderCallback, tmpRenderable);\n\t\t\t});\n\n\t\ttmpAnticipate.anticipate(\n\t\t\t(fAsyncTemplateCallback) =>\n\t\t\t{\n\t\t\t\t// Render the template (asynchronously)\n\t\t\t\tthis.pict.parseTemplateByHash(tmpRenderable.TemplateHash, tmpRecord,\n\t\t\t\t\t(pError, pContent) =>\n\t\t\t\t\t{\n\t\t\t\t\t\tif (pError)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render (asynchronously) ${tmpRenderableHash} (param ${pRenderableHash}) because it did not parse the template.`, pError);\n\t\t\t\t\t\t\treturn fAsyncTemplateCallback(pError);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttmpRenderable.Content = pContent;\n\n\t\t\t\t\t\treturn fAsyncTemplateCallback();\n\t\t\t\t\t}, [this], pScope, { RootRenderable: typeof pRootRenderable === 'object' ? pRootRenderable : tmpRenderable });\n\t\t\t});\n\n\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t{\n\t\t\tthis.onBeforeProjectAsync(fNext, tmpRenderable);\n\t\t});\n\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t{\n\t\t\tthis.onProjectAsync(fNext, tmpRenderable);\n\t\t});\n\n\t\tif (tmpRenderable.RenderMethod !== 'virtual-assignment')\n\t\t{\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tthis.onAfterProjectAsync(fNext, tmpRenderable);\n\t\t\t});\n\n\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tthis.onAfterRenderAsync(fNext, tmpRenderable);\n\t\t\t});\n\t\t}\n\n\t\ttmpAnticipate.wait(tmpCallback);\n\t}\n\n\t/**\n\t * Renders the default renderable.\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\trenderDefaultAsync(fCallback)\n\t{\n\t\t// Render the default renderable\n\t\tthis.renderAsync(fCallback);\n\t}\n\n\t/**\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbasicRender(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\treturn this.basicRenderWithScope(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t}\n\n\t/**\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbasicRenderWithScope(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\tlet tmpRenderOptions = this.buildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t\tif (tmpRenderOptions.Valid)\n\t\t{\n\t\t\tthis.assignRenderContent(tmpRenderOptions.Renderable, tmpRenderOptions.DestinationAddress, this.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash, tmpRenderOptions.Record, null, [this], pScope, { RootRenderable: tmpRenderOptions.Renderable }));\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not perform a basic render of ${tmpRenderOptions.RenderableHash} because it is not valid.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t */\n\tbasicRenderAsync(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback)\n\t{\n\t\treturn this.basicRenderWithScopeAsync(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback);\n\t}\n\n\t/**\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t */\n\tbasicRenderWithScopeAsync(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback)\n\t{\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateRecordAddress) === 'function') ? pTemplateRecordAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\tnull;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} basicRenderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} basicRenderAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tconst tmpRenderOptions = this.buildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t\tif (tmpRenderOptions.Valid)\n\t\t{\n\t\t\tthis.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash, tmpRenderOptions.Record,\n\t\t\t\t/**\n\t\t\t\t * @param {Error} [pError] - The error that occurred during template parsing.\n\t\t\t\t * @param {string} [pContent] - The content that was rendered from the template.\n\t\t\t\t */\n\t\t\t\t(pError, pContent) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render (asynchronously) ${tmpRenderOptions.RenderableHash} because it did not parse the template.`, pError);\n\t\t\t\t\t\treturn tmpCallback(pError);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.assignRenderContent(tmpRenderOptions.Renderable, tmpRenderOptions.DestinationAddress, pContent);\n\t\t\t\t\treturn tmpCallback();\n\t\t\t\t}, [this], pScope, { RootRenderable: tmpRenderOptions.Renderable });\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpErrorMessage = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not perform a basic render of ${tmpRenderOptions.RenderableHash} because it is not valid.`;\n\t\t\tthis.log.error(tmpErrorMessage);\n\t\t\treturn tmpCallback(new Error(tmpErrorMessage));\n\t\t}\n\t}\n\n\t/**\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonProject(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onProject:`);\n\t\t}\n\t\tif (pRenderable.RenderMethod === 'virtual-assignment')\n\t\t{\n\t\t\tthis.pict.TransactionTracking.pushToTransactionQueue(pRenderable.TransactionHash, { ViewHash: this.Hash, Renderable: pRenderable }, 'Deferred-Post-Content-Assignment');\n\t\t}\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Assigning Renderable[${pRenderable.RenderableHash}] content length ${pRenderable.Content.length} to Destination [${pRenderable.ContentDestinationAddress}] using Async render method ${pRenderable.RenderMethod}.`);\n\t\t}\n\n\t\t// Assign the content to the destination address\n\t\tthis.pict.ContentAssignment.projectContent(pRenderable.RenderMethod, pRenderable.ContentDestinationAddress, pRenderable.Content, pRenderable.TestAddress);\n\n\t\tthis.lastRenderedTimestamp = this.pict.log.getTimeStamp();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM (async flow).\n\t *\n\t * @param {(error?: Error, content?: string) => void} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that is being projected.\n\t */\n\tonProjectAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onProject(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is rendered.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonAfterRender(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRender:`);\n\t\t}\n\t\tif (pRenderable && pRenderable.RootRenderableViewHash === this.Hash)\n\t\t{\n\t\t\tconst tmpTransactionQueue = this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash) || [];\n\t\t\tfor (const tmpEvent of tmpTransactionQueue)\n\t\t\t{\n\t\t\t\tconst tmpView = this.pict.views[tmpEvent.Data.ViewHash];\n\t\t\t\tif (!tmpView)\n\t\t\t\t{\n\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRender: Could not find view for transaction hash ${pRenderable.TransactionHash} and ViewHash ${tmpEvent.Data.ViewHash}.`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttmpView.onAfterProject();\n\n\t\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\t\ttmpView.onAfterRender(tmpEvent.Data.Renderable);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is rendered (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonAfterRenderAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onAfterRender(pRenderable);\n\t\tconst tmpAnticipate = this.fable.newAnticipate();\n\t\tif (pRenderable && pRenderable.RootRenderableViewHash === this.Hash)\n\t\t{\n\t\t\tconst queue = this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash) || [];\n\t\t\tfor (const event of queue)\n\t\t\t{\n\t\t\t\t/** @type {PictView} */\n\t\t\t\tconst tmpView = this.pict.views[event.Data.ViewHash];\n\t\t\t\tif (!tmpView)\n\t\t\t\t{\n\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRenderAsync: Could not find view for transaction hash ${pRenderable.TransactionHash} and ViewHash ${event.Data.ViewHash}.`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(tmpView.onAfterProjectAsync.bind(tmpView));\n\t\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t\t{\n\t\t\t\t\ttmpView.onAfterRenderAsync(fNext, event.Data.Renderable);\n\t\t\t\t});\n\n\t\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\t}\n\t\t}\n\t\treturn tmpAnticipate.wait(fCallback);\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that was projected.\n\t */\n\tonAfterProject(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterProject:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that was projected.\n\t */\n\tonAfterProjectAsync(fCallback, pRenderable)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Solver */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is solved.\n\t */\n\tonBeforeSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeSolveAsync(fCallback)\n\t{\n\t\tthis.onBeforeSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is solved.\n\t */\n\tonSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonSolveAsync(fCallback)\n\t{\n\t\tthis.onSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Performs view solving and triggers lifecycle hooks.\n\t *\n\t * @return {boolean} - True if the view was solved successfully, false otherwise.\n\t */\n\tsolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeSolve();\n\t\tthis.onSolve();\n\t\tthis.onAfterSolve();\n\t\tthis.lastSolvedTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Performs view solving and triggers lifecycle hooks (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} solveAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSolvedTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is solved.\n\t */\n\tonAfterSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterSolveAsync(fCallback)\n\t{\n\t\tthis.onAfterSolve();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal From View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled from the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tonBeforeMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeMarshalFromViewAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled from the view.\n\t */\n\tonMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonMarshalFromViewAsync(fCallback)\n\t{\n\n\t\tthis.onMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Marshals data from the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tmarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeMarshalFromView();\n\t\tthis.onMarshalFromView();\n\t\tthis.onAfterMarshalFromView();\n\t\tthis.lastMarshalFromViewTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Marshals data from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tmarshalFromViewAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalFromViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onMarshalFromViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalFromViewAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} marshalFromViewAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalFromViewTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled from the view.\n\t */\n\tonAfterMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterMarshalFromViewAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal To View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled into the view.\n\t */\n\tonBeforeMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled into the view.\n\t */\n\tonMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Marshals data into the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tmarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeMarshalToView();\n\t\tthis.onMarshalToView();\n\t\tthis.onAfterMarshalToView();\n\t\tthis.lastMarshalToViewTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Marshals data into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tmarshalToViewAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalToViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onMarshalToViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalToViewAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} marshalToViewAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalToViewTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled into the view.\n\t */\n\tonAfterMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/** @return {boolean} - True if the object is a PictView. */\n\tget isPictView()\n\t{\n\t\treturn true;\n\t}\n}\n\nmodule.exports = PictView;\n","// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n","module.exports={\n\t\"Name\": \"Retold Data Cloner\",\n\t\"Hash\": \"DataCloner\",\n\t\"MainViewportViewIdentifier\": \"DataCloner-Layout\",\n\t\"MainViewportDestinationAddress\": \"#DataCloner-Application-Container\",\n\t\"MainViewportDefaultDataAddress\": \"AppData.DataCloner\",\n\t\"pict_configuration\": { \"Product\": \"DataCloner\" },\n\t\"AutoRenderMainViewportViewAfterInitialize\": false\n}\n","const libPictApplication = require('pict-application');\n\nconst libProvider = require('./providers/Pict-Provider-DataCloner.js');\n\nconst libViewLayout = require('./views/PictView-DataCloner-Layout.js');\nconst libViewConnection = require('./views/PictView-DataCloner-Connection.js');\nconst libViewSession = require('./views/PictView-DataCloner-Session.js');\nconst libViewSchema = require('./views/PictView-DataCloner-Schema.js');\nconst libViewDeploy = require('./views/PictView-DataCloner-Deploy.js');\nconst libViewSync = require('./views/PictView-DataCloner-Sync.js');\nconst libViewExport = require('./views/PictView-DataCloner-Export.js');\nconst libViewViewData = require('./views/PictView-DataCloner-ViewData.js');\nconst libViewHistogram = require('pict-section-histogram');\n\nclass DataClonerApplication extends libPictApplication\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\n\t\t// Register provider\n\t\tthis.pict.addProvider('DataCloner', libProvider.default_configuration, libProvider);\n\n\t\t// Register views\n\t\tthis.pict.addView('DataCloner-Layout', libViewLayout.default_configuration, libViewLayout);\n\t\tthis.pict.addView('DataCloner-Connection', libViewConnection.default_configuration, libViewConnection);\n\t\tthis.pict.addView('DataCloner-Session', libViewSession.default_configuration, libViewSession);\n\t\tthis.pict.addView('DataCloner-Schema', libViewSchema.default_configuration, libViewSchema);\n\t\tthis.pict.addView('DataCloner-Deploy', libViewDeploy.default_configuration, libViewDeploy);\n\t\tthis.pict.addView('DataCloner-Sync', libViewSync.default_configuration, libViewSync);\n\t\tthis.pict.addView('DataCloner-Export', libViewExport.default_configuration, libViewExport);\n\t\tthis.pict.addView('DataCloner-ViewData', libViewViewData.default_configuration, libViewViewData);\n\t\tthis.pict.addView('DataCloner-StatusHistogram',\n\t\t\t{\n\t\t\t\tViewIdentifier: 'DataCloner-StatusHistogram',\n\t\t\t\tTargetElementAddress: '#DataCloner-Throughput-Histogram',\n\t\t\t\tDefaultDestinationAddress: '#DataCloner-Throughput-Histogram',\n\t\t\t\tRenderOnLoad: false,\n\t\t\t\tSelectable: false,\n\t\t\t\tOrientation: 'vertical',\n\t\t\t\tFillContainer: true,\n\t\t\t\tShowValues: false,\n\t\t\t\tShowLabels: true,\n\t\t\t\tMaxBarSize: 80,\n\t\t\t\tBarColor: '#4a90d9',\n\t\t\t\tBins: []\n\t\t\t}, libViewHistogram);\n\t}\n\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\t// Centralized state (replaces global variables)\n\t\tthis.pict.AppData.DataCloner =\n\t\t{\n\t\t\tFetchedTables: [],\n\t\t\tDeployedTables: [],\n\t\t\tLastReport: null,\n\t\t\tServerBusyAtLoad: false,\n\t\t\tSyncPollTimer: null,\n\t\t\tLiveStatusTimer: null,\n\t\t\tStatusDetailExpanded: false,\n\t\t\tStatusDetailTimer: null,\n\t\t\tStatusDetailData: null,\n\t\t\tLastLiveStatus: null,\n\t\t\tPersistFields: [\n\t\t\t\t'serverURL', 'authMethod', 'authURI', 'checkURI',\n\t\t\t\t'cookieName', 'cookieValueAddr', 'cookieValueTemplate', 'loginMarker',\n\t\t\t\t'userName', 'password', 'schemaURL', 'pageSize', 'dateTimePrecisionMS',\n\t\t\t\t'connProvider', 'sqliteFilePath',\n\t\t\t\t'mysqlServer', 'mysqlPort', 'mysqlUser', 'mysqlPassword', 'mysqlDatabase', 'mysqlConnectionLimit',\n\t\t\t\t'mssqlServer', 'mssqlPort', 'mssqlUser', 'mssqlPassword', 'mssqlDatabase', 'mssqlConnectionLimit',\n\t\t\t\t'postgresqlHost', 'postgresqlPort', 'postgresqlUser', 'postgresqlPassword', 'postgresqlDatabase', 'postgresqlConnectionLimit',\n\t\t\t\t'solrHost', 'solrPort', 'solrCore', 'solrPath',\n\t\t\t\t'mongodbHost', 'mongodbPort', 'mongodbUser', 'mongodbPassword', 'mongodbDatabase', 'mongodbConnectionLimit',\n\t\t\t\t'rocksdbFolder',\n\t\t\t\t'bibliographFolder',\n\t\t\t\t'syncMaxRecords'\n\t\t\t]\n\t\t};\n\n\t\t// Make pict available for inline onclick handlers\n\t\twindow.pict = this.pict;\n\n\t\t// Render layout (which chains child view renders via onAfterRender)\n\t\tthis.pict.views['DataCloner-Layout'].render();\n\n\t\t// Post-render initialization\n\t\tthis.pict.providers.DataCloner.initPersistence();\n\t\tthis.pict.views['DataCloner-Connection'].onProviderChange();\n\t\tthis.pict.providers.DataCloner.restoreDeployedTables();\n\t\tthis.pict.providers.DataCloner.startLiveStatusPolling();\n\t\tthis.pict.providers.DataCloner.initAccordionPreviews();\n\t\tthis.pict.providers.DataCloner.updateAllPreviews();\n\t\tthis.pict.views['DataCloner-Layout'].collapseAllSections();\n\t\tthis.pict.providers.DataCloner.initAutoProcess();\n\n\t\treturn fCallback();\n\t}\n}\n\nmodule.exports = DataClonerApplication;\n\nmodule.exports.default_configuration = require('./Pict-Application-DataCloner-Configuration.json');\n","module.exports = { DataClonerApplication: require('./Pict-Application-DataCloner.js') };\n\nif (typeof(window) !== 'undefined')\n{\n\twindow.DataClonerApplication = module.exports.DataClonerApplication;\n}\n","const libPictProvider = require('pict-provider');\n\nclass DataClonerProvider extends libPictProvider\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\t// ================================================================\n\t// API Helper\n\t// ================================================================\n\n\tapi(pMethod, pPath, pBody)\n\t{\n\t\tlet tmpOpts = { method: pMethod, headers: {} };\n\t\tif (pBody)\n\t\t{\n\t\t\ttmpOpts.headers['Content-Type'] = 'application/json';\n\t\t\ttmpOpts.body = JSON.stringify(pBody);\n\t\t}\n\t\treturn fetch(pPath, tmpOpts).then(function(pResponse) { return pResponse.json(); });\n\t}\n\n\tsetStatus(pElementId, pMessage, pType)\n\t{\n\t\tlet tmpEl = document.getElementById(pElementId);\n\t\tif (!tmpEl) return;\n\t\ttmpEl.className = 'status ' + (pType || 'info');\n\t\ttmpEl.textContent = pMessage;\n\t\ttmpEl.style.display = 'block';\n\t}\n\n\tescapeHtml(pStr)\n\t{\n\t\tlet tmpDiv = document.createElement('div');\n\t\ttmpDiv.appendChild(document.createTextNode(pStr));\n\t\treturn tmpDiv.innerHTML;\n\t}\n\n\t// ================================================================\n\t// Phase status indicators\n\t// ================================================================\n\n\tsetSectionPhase(pSection, pState)\n\t{\n\t\tlet tmpEl = document.getElementById('phase' + pSection);\n\t\tif (!tmpEl) return;\n\n\t\ttmpEl.className = 'accordion-phase';\n\n\t\tif (pState === 'ok')\n\t\t{\n\t\t\ttmpEl.innerHTML = '✓';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-ok');\n\t\t}\n\t\telse if (pState === 'error')\n\t\t{\n\t\t\ttmpEl.innerHTML = '✗';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-error');\n\t\t}\n\t\telse if (pState === 'busy')\n\t\t{\n\t\t\ttmpEl.innerHTML = '<span class=\"phase-spinner\"></span>';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-busy');\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpEl.innerHTML = '';\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Accordion Previews\n\t// ================================================================\n\n\tupdateAllPreviews()\n\t{\n\t\t// Section 1 — Database Connection\n\t\tlet tmpProvider = document.getElementById('connProvider');\n\t\tif (!tmpProvider) return;\n\t\ttmpProvider = tmpProvider.value;\n\t\tlet tmpPreview1 = tmpProvider;\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\tlet tmpPath = document.getElementById('sqliteFilePath').value || 'data/cloned.sqlite';\n\t\t\ttmpPreview1 = 'SQLite at ' + tmpPath;\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mysqlServer').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mysqlPort').value || '3306';\n\t\t\tlet tmpUser = document.getElementById('mysqlUser').value || 'root';\n\t\t\ttmpPreview1 = 'MySQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mssqlServer').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mssqlPort').value || '1433';\n\t\t\tlet tmpUser = document.getElementById('mssqlUser').value || 'sa';\n\t\t\ttmpPreview1 = 'MSSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('postgresqlHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('postgresqlPort').value || '5432';\n\t\t\tlet tmpUser = document.getElementById('postgresqlUser').value || 'postgres';\n\t\t\ttmpPreview1 = 'PostgreSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'MongoDB')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mongodbHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mongodbPort').value || '27017';\n\t\t\ttmpPreview1 = 'MongoDB on ' + tmpHost + ':' + tmpPort;\n\t\t}\n\t\telse if (tmpProvider === 'Solr')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('solrHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('solrPort').value || '8983';\n\t\t\ttmpPreview1 = 'Solr on ' + tmpHost + ':' + tmpPort;\n\t\t}\n\t\telse if (tmpProvider === 'RocksDB')\n\t\t{\n\t\t\tlet tmpFolder = document.getElementById('rocksdbFolder').value || 'data/rocksdb';\n\t\t\ttmpPreview1 = 'RocksDB at ' + tmpFolder;\n\t\t}\n\t\telse if (tmpProvider === 'Bibliograph')\n\t\t{\n\t\t\tlet tmpFolder = document.getElementById('bibliographFolder').value || 'data/bibliograph';\n\t\t\ttmpPreview1 = 'Bibliograph at ' + tmpFolder;\n\t\t}\n\t\tdocument.getElementById('preview1').textContent = tmpPreview1;\n\n\t\t// Section 2 — Remote Session\n\t\tlet tmpServerURL = document.getElementById('serverURL').value;\n\t\tlet tmpUserName = document.getElementById('userName').value;\n\t\tif (tmpServerURL)\n\t\t{\n\t\t\tlet tmpPreview2 = tmpServerURL;\n\t\t\tif (tmpUserName) tmpPreview2 += ' as ' + tmpUserName;\n\t\t\tdocument.getElementById('preview2').textContent = tmpPreview2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview2').textContent = 'Configure remote server URL and credentials';\n\t\t}\n\n\t\t// Section 3 — Remote Schema\n\t\tlet tmpTableChecks = document.querySelectorAll('#tableList input[type=\"checkbox\"]:checked');\n\t\tif (tmpTableChecks.length > 0)\n\t\t{\n\t\t\tdocument.getElementById('preview3').textContent = tmpTableChecks.length + ' table' + (tmpTableChecks.length === 1 ? '' : 's') + ' selected';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value;\n\t\t\tif (tmpSchemaURL)\n\t\t\t{\n\t\t\t\tdocument.getElementById('preview3').textContent = 'Schema from ' + tmpSchemaURL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById('preview3').textContent = 'Fetch and select tables from the remote server';\n\t\t\t}\n\t\t}\n\n\t\t// Section 4 — Deploy Schema\n\t\tlet tmpDeployedEl = document.getElementById('deployStatus');\n\t\tlet tmpDeployedText = tmpDeployedEl ? tmpDeployedEl.textContent : '';\n\t\tif (tmpDeployedText && tmpDeployedText.indexOf('deployed') !== -1)\n\t\t{\n\t\t\tdocument.getElementById('preview4').textContent = tmpDeployedText;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview4').textContent = 'Create selected tables in the local database';\n\t\t}\n\n\t\t// Section 5 — Synchronize Data\n\t\tlet tmpSyncMode = document.querySelector('input[name=\"syncMode\"]:checked');\n\t\tlet tmpModeName = tmpSyncMode ? tmpSyncMode.value : 'Initial';\n\t\tlet tmpPageSize = document.getElementById('pageSize').value || '100';\n\t\tlet tmpSyncPreview = tmpModeName + ' sync, page size ' + tmpPageSize;\n\t\tlet tmpDeleted = document.getElementById('syncDeletedRecords').checked;\n\t\tif (tmpDeleted) tmpSyncPreview += ', including deleted';\n\t\tdocument.getElementById('preview5').textContent = tmpSyncPreview;\n\n\t\t// Section 6 — Export Configuration\n\t\tlet tmpMaxRecords = document.getElementById('syncMaxRecords').value;\n\t\tlet tmpLogFile = document.getElementById('syncLogFile').checked;\n\t\tlet tmpExportParts = [];\n\t\tif (tmpMaxRecords && parseInt(tmpMaxRecords, 10) > 0) tmpExportParts.push('max ' + tmpMaxRecords + ' records');\n\t\tif (tmpLogFile) tmpExportParts.push('log enabled');\n\t\telse tmpExportParts.push('log disabled');\n\t\tdocument.getElementById('preview6').textContent = tmpExportParts.length > 0 ? 'Export: ' + tmpExportParts.join(', ') : 'Generate JSON config for headless cloning';\n\n\t\t// Section 7 — View Data\n\t\tlet tmpViewTable = document.getElementById('viewTable').value;\n\t\tif (tmpViewTable)\n\t\t{\n\t\t\tdocument.getElementById('preview7').textContent = 'Viewing ' + tmpViewTable;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview7').textContent = 'Browse synced table data';\n\t\t}\n\t}\n\n\tinitAccordionPreviews()\n\t{\n\t\tlet tmpSelf = this;\n\n\t\tlet tmpPreviewFields = [\n\t\t\t'connProvider', 'sqliteFilePath',\n\t\t\t'mysqlServer', 'mysqlPort', 'mysqlUser',\n\t\t\t'mssqlServer', 'mssqlPort', 'mssqlUser',\n\t\t\t'postgresqlHost', 'postgresqlPort', 'postgresqlUser',\n\t\t\t'mongodbHost', 'mongodbPort',\n\t\t\t'solrHost', 'solrPort',\n\t\t\t'rocksdbFolder', 'bibliographFolder',\n\t\t\t'serverURL', 'userName',\n\t\t\t'schemaURL',\n\t\t\t'pageSize', 'dateTimePrecisionMS',\n\t\t\t'syncMaxRecords',\n\t\t\t'viewTable', 'viewLimit'\n\t\t];\n\n\t\tlet tmpHandler = function() { tmpSelf.updateAllPreviews(); };\n\n\t\tfor (let i = 0; i < tmpPreviewFields.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById(tmpPreviewFields[i]);\n\t\t\tif (tmpEl)\n\t\t\t{\n\t\t\t\ttmpEl.addEventListener('input', tmpHandler);\n\t\t\t\ttmpEl.addEventListener('change', tmpHandler);\n\t\t\t}\n\t\t}\n\n\t\t// Checkboxes and radios\n\t\tlet tmpCheckboxes = ['syncDeletedRecords', 'syncLogFile'];\n\t\tfor (let i = 0; i < tmpCheckboxes.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById(tmpCheckboxes[i]);\n\t\t\tif (tmpEl) tmpEl.addEventListener('change', tmpHandler);\n\t\t}\n\n\t\tdocument.querySelectorAll('input[name=\"syncMode\"]').forEach(function(pEl)\n\t\t{\n\t\t\tpEl.addEventListener('change', tmpHandler);\n\t\t});\n\t}\n\n\t// ================================================================\n\t// LocalStorage Persistence\n\t// ================================================================\n\n\tsaveField(pFieldId)\n\t{\n\t\tlet tmpEl = document.getElementById(pFieldId);\n\t\tif (tmpEl)\n\t\t{\n\t\t\tlocalStorage.setItem('dataCloner_' + pFieldId, tmpEl.value);\n\t\t}\n\t}\n\n\trestoreFields()\n\t{\n\t\tlet tmpPersistFields = this.pict.AppData.DataCloner.PersistFields;\n\t\tfor (let i = 0; i < tmpPersistFields.length; i++)\n\t\t{\n\t\t\tlet tmpId = tmpPersistFields[i];\n\t\t\tlet tmpSaved = localStorage.getItem('dataCloner_' + tmpId);\n\t\t\tif (tmpSaved !== null)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(tmpId);\n\t\t\t\tif (tmpEl) tmpEl.value = tmpSaved;\n\t\t\t}\n\t\t}\n\n\t\t// Restore checkbox state\n\t\tlet tmpSyncDeleted = localStorage.getItem('dataCloner_syncDeletedRecords');\n\t\tif (tmpSyncDeleted !== null)\n\t\t{\n\t\t\tdocument.getElementById('syncDeletedRecords').checked = tmpSyncDeleted === 'true';\n\t\t}\n\t\t// Restore sync mode\n\t\tlet tmpSyncMode = localStorage.getItem('dataCloner_syncMode');\n\t\tif (tmpSyncMode === 'Ongoing')\n\t\t{\n\t\t\tdocument.getElementById('syncModeOngoing').checked = true;\n\t\t}\n\t\tlet tmpSolrSecure = localStorage.getItem('dataCloner_solrSecure');\n\t\tif (tmpSolrSecure !== null)\n\t\t{\n\t\t\tdocument.getElementById('solrSecure').checked = tmpSolrSecure === 'true';\n\t\t}\n\t\t// Restore advanced ID pagination checkbox\n\t\tlet tmpAdvancedIDPagination = localStorage.getItem('dataCloner_syncAdvancedIDPagination');\n\t\tif (tmpAdvancedIDPagination !== null)\n\t\t{\n\t\t\tdocument.getElementById('syncAdvancedIDPagination').checked = tmpAdvancedIDPagination === 'true';\n\t\t}\n\t}\n\n\tinitPersistence()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.restoreFields();\n\n\t\tlet tmpPersistFields = this.pict.AppData.DataCloner.PersistFields;\n\t\tfor (let i = 0; i < tmpPersistFields.length; i++)\n\t\t{\n\t\t\t(function(pId)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(pId);\n\t\t\t\tif (tmpEl)\n\t\t\t\t{\n\t\t\t\t\ttmpEl.addEventListener('input', function() { tmpSelf.saveField(pId); });\n\t\t\t\t\ttmpEl.addEventListener('change', function() { tmpSelf.saveField(pId); });\n\t\t\t\t}\n\t\t\t})(tmpPersistFields[i]);\n\t\t}\n\n\t\t// Persist sync deleted checkbox\n\t\tlet tmpSyncDeletedEl = document.getElementById('syncDeletedRecords');\n\t\tif (tmpSyncDeletedEl)\n\t\t{\n\t\t\ttmpSyncDeletedEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncDeletedRecords', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist sync mode radio\n\t\tdocument.querySelectorAll('input[name=\"syncMode\"]').forEach(function(pEl)\n\t\t{\n\t\t\tpEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncMode', this.value);\n\t\t\t});\n\t\t});\n\n\t\t// Persist solr secure checkbox\n\t\tlet tmpSolrSecureEl = document.getElementById('solrSecure');\n\t\tif (tmpSolrSecureEl)\n\t\t{\n\t\t\ttmpSolrSecureEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_solrSecure', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist advanced ID pagination checkbox\n\t\tlet tmpAdvancedIDPaginationEl = document.getElementById('syncAdvancedIDPagination');\n\t\tif (tmpAdvancedIDPaginationEl)\n\t\t{\n\t\t\ttmpAdvancedIDPaginationEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncAdvancedIDPagination', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist auto-process checkboxes\n\t\tlet tmpAutoIds = ['auto1', 'auto2', 'auto3', 'auto4', 'auto5'];\n\t\tfor (let a = 0; a < tmpAutoIds.length; a++)\n\t\t{\n\t\t\t(function(pId)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(pId);\n\t\t\t\tif (tmpEl)\n\t\t\t\t{\n\t\t\t\t\tlet tmpSaved = localStorage.getItem('dataCloner_' + pId);\n\t\t\t\t\tif (tmpSaved !== null) tmpEl.checked = tmpSaved === 'true';\n\t\t\t\t\ttmpEl.addEventListener('change', function()\n\t\t\t\t\t{\n\t\t\t\t\t\tlocalStorage.setItem('dataCloner_' + pId, this.checked);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})(tmpAutoIds[a]);\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Live Status Indicator\n\t// ================================================================\n\n\tstartLiveStatusPolling()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\tif (tmpAppData.LiveStatusTimer) clearInterval(tmpAppData.LiveStatusTimer);\n\t\tthis.pollLiveStatus();\n\t\tlet tmpSelf = this;\n\t\ttmpAppData.LiveStatusTimer = setInterval(function() { tmpSelf.pollLiveStatus(); }, 1500);\n\t}\n\n\tpollLiveStatus()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/live-status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.renderLiveStatus(pData);\n\t\t\t})\n\t\t\t.catch(function()\n\t\t\t{\n\t\t\t\ttmpSelf.renderLiveStatus({ Phase: 'disconnected', Message: 'Cannot reach server', TotalSynced: 0, TotalRecords: 0 });\n\t\t\t});\n\t}\n\n\trenderLiveStatus(pData)\n\t{\n\t\t// Cache the live status data for the detail view\n\t\tthis.pict.AppData.DataCloner.LastLiveStatus = pData;\n\n\t\tlet tmpBar = document.getElementById('liveStatusBar');\n\t\tlet tmpMsg = document.getElementById('liveStatusMessage');\n\t\tlet tmpMeta = document.getElementById('liveStatusMeta');\n\t\tlet tmpProgressFill = document.getElementById('liveStatusProgressFill');\n\t\tif (!tmpBar) return;\n\n\t\t// Update phase class (preserve expanded class if present)\n\t\tlet tmpWasExpanded = tmpBar.classList.contains('expanded');\n\t\ttmpBar.className = 'live-status-bar phase-' + (pData.Phase || 'idle');\n\t\tif (tmpWasExpanded) tmpBar.classList.add('expanded');\n\n\t\t// Update message\n\t\ttmpMsg.textContent = pData.Message || 'Idle';\n\n\t\t// Update meta info\n\t\tlet tmpMetaParts = [];\n\t\tif (pData.Phase === 'syncing' || pData.Phase === 'stopping')\n\t\t{\n\t\t\tif (pData.Elapsed)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + pData.Elapsed + '</span>');\n\t\t\t}\n\t\t\tif (pData.ETA)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">~' + pData.ETA + ' remaining</span>');\n\t\t\t}\n\t\t\tif (pData.TotalTables > 0)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + pData.Completed + '</strong> / ' + pData.TotalTables + ' tables</span>');\n\t\t\t}\n\t\t\tif (pData.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = pData.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\tif (pData.PreCountGrandTotal > 0)\n\t\t\t\t{\n\t\t\t\t\tlet tmpGrandTotal = pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> / ' + tmpGrandTotal + ' records</span>');\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (pData.PreCountGrandTotal > 0)\n\t\t\t{\n\t\t\t\tlet tmpGrandTotal = pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">' + tmpGrandTotal + ' records to sync</span>');\n\t\t\t}\n\t\t\tif (pData.PreCountProgress && pData.PreCountProgress.Counted < pData.PreCountProgress.TotalTables)\n\t\t\t{\n\t\t\t\tlet tmpCountedSoFar = pData.PreCountGrandTotal > 0\n\t\t\t\t\t? ' (' + pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + ' records found)'\n\t\t\t\t\t: '';\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">counting: ' + pData.PreCountProgress.Counted + ' / ' + pData.PreCountProgress.TotalTables + ' tables' + tmpCountedSoFar + '</span>');\n\t\t\t}\n\t\t\tif (pData.Errors > 0)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\" style=\"color:#dc3545\"><strong>' + pData.Errors + '</strong> error' + (pData.Errors === 1 ? '' : 's') + '</span>');\n\t\t\t}\n\t\t}\n\t\telse if (pData.Phase === 'complete')\n\t\t{\n\t\t\tif (pData.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = pData.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records synced</span>');\n\t\t\t}\n\t\t}\n\t\ttmpMeta.innerHTML = tmpMetaParts.join('');\n\n\t\t// Update progress bar\n\t\tlet tmpPct = 0;\n\t\tif (pData.Phase === 'syncing' && pData.PreCountProgress && pData.PreCountProgress.Counted < pData.PreCountProgress.TotalTables)\n\t\t{\n\t\t\t// During counting phase, show table counting progress\n\t\t\ttmpPct = Math.min((pData.PreCountProgress.Counted / pData.PreCountProgress.TotalTables) * 100, 99);\n\t\t}\n\t\telse if (pData.Phase === 'syncing' && pData.PreCountGrandTotal > 0 && pData.TotalSynced > 0)\n\t\t{\n\t\t\ttmpPct = Math.min((pData.TotalSynced / pData.PreCountGrandTotal) * 100, 99.9);\n\t\t}\n\t\telse if (pData.Phase === 'syncing' && pData.TotalTables > 0)\n\t\t{\n\t\t\tlet tmpTablePct = (pData.Completed / pData.TotalTables) * 100;\n\t\t\tif (pData.ActiveProgress && pData.ActiveProgress.Total > 0)\n\t\t\t{\n\t\t\t\tlet tmpEntityPct = (pData.ActiveProgress.Synced / pData.ActiveProgress.Total) * (100 / pData.TotalTables);\n\t\t\t\ttmpPct = tmpTablePct + tmpEntityPct;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpPct = tmpTablePct;\n\t\t\t}\n\t\t}\n\t\telse if (pData.Phase === 'complete')\n\t\t{\n\t\t\ttmpPct = 100;\n\t\t}\n\t\ttmpProgressFill.style.width = Math.min(100, Math.round(tmpPct)) + '%';\n\n\t\t// Auto-expand the detail view when sync starts so users see counting progress\n\t\tif ((pData.Phase === 'syncing' || pData.Phase === 'stopping') && !this.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t{\n\t\t\tlet tmpLayoutView = this.pict.views['DataCloner-Layout'];\n\t\t\tif (tmpLayoutView && typeof tmpLayoutView.toggleStatusDetail === 'function')\n\t\t\t{\n\t\t\t\ttmpLayoutView.toggleStatusDetail();\n\t\t\t}\n\t\t}\n\n\t\t// If the detail view is expanded, re-render it with fresh data\n\t\tif (this.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t{\n\t\t\tthis.renderStatusDetail();\n\t\t}\n\n\t\t// Auto-fetch the sync report when we detect a completed sync but haven't loaded the report yet\n\t\tif (pData.Phase === 'complete' && !this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tlet tmpSelf = this;\n\t\t\tthis.api('GET', '/clone/sync/report')\n\t\t\t\t.then(function(pReportData)\n\t\t\t\t{\n\t\t\t\t\tif (pReportData && pReportData.ReportVersion)\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.LastReport = pReportData;\n\t\t\t\t\t\tif (tmpSelf.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.renderStatusDetail();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch(function() { /* ignore fetch errors */ });\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Status Detail Expansion\n\t// ================================================================\n\n\tonStatusDetailExpanded()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\ttmpAppData.StatusDetailExpanded = true;\n\n\t\t// Immediate render from whatever data we have\n\t\tthis.renderStatusDetail();\n\n\t\t// Start detail polling (poll /sync/status for per-table data)\n\t\tif (tmpAppData.StatusDetailTimer) clearInterval(tmpAppData.StatusDetailTimer);\n\t\tlet tmpSelf = this;\n\t\ttmpAppData.StatusDetailTimer = setInterval(function() { tmpSelf.pollStatusDetail(); }, 2000);\n\t\tthis.pollStatusDetail();\n\t}\n\n\tonStatusDetailCollapsed()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\ttmpAppData.StatusDetailExpanded = false;\n\n\t\tif (tmpAppData.StatusDetailTimer)\n\t\t{\n\t\t\tclearInterval(tmpAppData.StatusDetailTimer);\n\t\t\ttmpAppData.StatusDetailTimer = null;\n\t\t}\n\t}\n\n\tpollStatusDetail()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.AppData.DataCloner.StatusDetailData = pData;\n\t\t\t\ttmpSelf.renderStatusDetail();\n\t\t\t})\n\t\t\t.catch(function() { /* ignore poll errors */ });\n\t}\n\n\trenderCountingPhaseDetail(pContainer, pPreCountProgress)\n\t{\n\t\tlet tmpTables = pPreCountProgress.Tables || [];\n\t\tlet tmpCounted = pPreCountProgress.Counted || 0;\n\t\tlet tmpTotal = pPreCountProgress.TotalTables || 0;\n\t\tlet tmpRunningTotal = 0;\n\n\t\tlet tmpHtml = '<div class=\"status-detail-section\">';\n\t\ttmpHtml += '<div class=\"status-detail-section-title\">Counting Records (' + tmpCounted + ' / ' + tmpTotal + ' tables)</div>';\n\n\t\tif (tmpTables.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<table class=\"precount-table\">';\n\t\t\ttmpHtml += '<thead><tr><th>Table</th><th style=\"text-align:right\">Records</th><th style=\"text-align:right\">Time</th></tr></thead>';\n\t\t\ttmpHtml += '<tbody>';\n\t\t\tfor (let i = 0; i < tmpTables.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpT = tmpTables[i];\n\t\t\t\ttmpRunningTotal += tmpT.Count;\n\t\t\t\tlet tmpCountFmt = this.formatNumber(tmpT.Count);\n\t\t\t\tlet tmpTimeFmt = tmpT.ElapsedMs < 1000\n\t\t\t\t\t? tmpT.ElapsedMs + 'ms'\n\t\t\t\t\t: (tmpT.ElapsedMs / 1000).toFixed(1) + 's';\n\t\t\t\tlet tmpRowClass = tmpT.Error ? ' class=\"precount-error\"' : '';\n\t\t\t\ttmpHtml += '<tr' + tmpRowClass + '>';\n\t\t\t\ttmpHtml += '<td>' + this.escapeHtml(tmpT.Name) + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums\">' + tmpCountFmt + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums; color:#888\">' + tmpTimeFmt + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</tbody>';\n\t\t\ttmpHtml += '<tfoot><tr>';\n\t\t\ttmpHtml += '<td><strong>Total</strong></td>';\n\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums\"><strong>' + this.formatNumber(tmpRunningTotal) + '</strong></td>';\n\t\t\ttmpHtml += '<td></td>';\n\t\t\ttmpHtml += '</tr></tfoot>';\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// Show pending indicator for remaining tables\n\t\tlet tmpRemaining = tmpTotal - tmpCounted;\n\t\tif (tmpRemaining > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"precount-pending\">';\n\t\t\ttmpHtml += '<span class=\"precount-spinner\"></span> ';\n\t\t\ttmpHtml += tmpRemaining + ' table' + (tmpRemaining === 1 ? '' : 's') + ' remaining…';\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\tpContainer.innerHTML = tmpHtml;\n\t}\n\n\trenderStatusDetail()\n\t{\n\t\tlet tmpContainer = document.getElementById('DataCloner-StatusDetail-Container');\n\t\tif (!tmpContainer) return;\n\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\tlet tmpLiveStatus = tmpAppData.LastLiveStatus;\n\t\tlet tmpStatusData = tmpAppData.StatusDetailData;\n\t\tlet tmpReport = tmpAppData.LastReport;\n\n\t\t// During the counting phase, show per-table counts as they arrive\n\t\tif (tmpLiveStatus && tmpLiveStatus.PreCountProgress\n\t\t\t&& tmpLiveStatus.PreCountProgress.Tables\n\t\t\t&& tmpLiveStatus.Phase === 'syncing'\n\t\t\t&& tmpLiveStatus.PreCountProgress.Counted < tmpLiveStatus.PreCountProgress.TotalTables)\n\t\t{\n\t\t\tthis.renderCountingPhaseDetail(tmpContainer, tmpLiveStatus.PreCountProgress);\n\t\t\t// Hide histogram during counting\n\t\t\tlet tmpHistContainer = document.getElementById('DataCloner-Throughput-Histogram');\n\t\t\tif (tmpHistContainer) tmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine data source: live during sync, report after sync\n\t\tlet tmpTables = {};\n\t\tlet tmpThroughputSamples = [];\n\t\tlet tmpEventLog = [];\n\t\tlet tmpIsLive = false;\n\n\t\tif (tmpLiveStatus && (tmpLiveStatus.Phase === 'syncing' || tmpLiveStatus.Phase === 'stopping'))\n\t\t{\n\t\t\ttmpIsLive = true;\n\t\t\tif (tmpStatusData && tmpStatusData.Tables) tmpTables = tmpStatusData.Tables;\n\t\t\tif (tmpLiveStatus.ThroughputSamples) tmpThroughputSamples = tmpLiveStatus.ThroughputSamples;\n\t\t}\n\t\telse if (tmpReport && tmpReport.ReportVersion)\n\t\t{\n\t\t\t// Build tables object from report\n\t\t\tfor (let i = 0; i < tmpReport.Tables.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpT = tmpReport.Tables[i];\n\t\t\t\ttmpTables[tmpT.Name] = tmpT;\n\t\t\t}\n\t\t\ttmpThroughputSamples = tmpReport.ThroughputSamples || [];\n\t\t\ttmpEventLog = tmpReport.EventLog || [];\n\t\t}\n\t\telse if (tmpStatusData && tmpStatusData.Tables)\n\t\t{\n\t\t\ttmpTables = tmpStatusData.Tables;\n\t\t\t// Use throughput samples from live status if available (e.g. after page reload with completed sync)\n\t\t\tif (tmpLiveStatus && tmpLiveStatus.ThroughputSamples)\n\t\t\t{\n\t\t\t\ttmpThroughputSamples = tmpLiveStatus.ThroughputSamples;\n\t\t\t}\n\t\t}\n\n\t\t// Categorize tables\n\t\tlet tmpRunning = [];\n\t\tlet tmpPending = [];\n\t\tlet tmpCompleted = [];\n\t\tlet tmpErrors = [];\n\t\tlet tmpTableNames = Object.keys(tmpTables);\n\n\t\tfor (let i = 0; i < tmpTableNames.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpTableNames[i];\n\t\t\tlet tmpT = tmpTables[tmpName];\n\t\t\tif (tmpT.Status === 'Syncing')\n\t\t\t{\n\t\t\t\ttmpRunning.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Pending')\n\t\t\t{\n\t\t\t\ttmpPending.push(tmpName);\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Complete')\n\t\t\t{\n\t\t\t\ttmpCompleted.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Error' || tmpT.Status === 'Partial')\n\t\t\t{\n\t\t\t\ttmpErrors.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t}\n\n\t\tlet tmpHtml = '';\n\n\t\t// === Section 1: Running Operations ===\n\t\tif (tmpRunning.length > 0 || tmpPending.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Running</div>';\n\t\t\tfor (let i = 0; i < tmpRunning.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpOp = tmpRunning[i];\n\t\t\t\tlet tmpPct = tmpOp.Data.Total > 0 ? Math.round((tmpOp.Data.Synced / tmpOp.Data.Total) * 100) : 0;\n\t\t\t\tlet tmpSyncedFmt = this.formatNumber(tmpOp.Data.Synced || 0);\n\t\t\t\tlet tmpTotalFmt = this.formatNumber(tmpOp.Data.Total || 0);\n\t\t\t\ttmpHtml += '<div class=\"running-op-row\">';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-name\">' + this.escapeHtml(tmpOp.Name) + '</div>';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-bar\"><div class=\"running-op-bar-fill\" style=\"width:' + tmpPct + '%\"></div></div>';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-count\">' + tmpSyncedFmt + ' / ' + tmpTotalFmt + ' (' + tmpPct + '%)</div>';\n\t\t\t\ttmpHtml += '</div>';\n\t\t\t}\n\t\t\tif (tmpPending.length > 0)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"running-op-pending\">' + tmpPending.length + ' table' + (tmpPending.length === 1 ? '' : 's') + ' waiting</div>';\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\t// === Section 2: Completed Successful Operations ===\n\t\tif (tmpCompleted.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Completed (' + tmpCompleted.length + ')</div>';\n\n\t\t\tfor (let i = 0; i < tmpCompleted.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += this.renderCompletedRow(tmpCompleted[i]);\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\t// === Section 3: Unsuccessful Operations ===\n\t\tif (tmpErrors.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Errors (' + tmpErrors.length + ')</div>';\n\t\t\tfor (let i = 0; i < tmpErrors.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += this.renderErrorRow(tmpErrors[i], tmpEventLog);\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\tif (tmpHtml === '')\n\t\t{\n\t\t\tif (tmpIsLive)\n\t\t\t{\n\t\t\t\ttmpHtml = '<div style=\"font-size:0.9em; color:#888; padding:8px 0\">Sync in progress, waiting for table data\\u2026</div>';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpHtml = '<div style=\"font-size:0.9em; color:#888; padding:8px 0\">No sync data available. Run a sync to see operation details here.</div>';\n\t\t\t}\n\t\t}\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\n\t\t// Update the throughput histogram via pict-section-histogram\n\t\tthis.updateThroughputHistogram(tmpThroughputSamples);\n\t}\n\n\tupdateThroughputHistogram(pSamples)\n\t{\n\t\tlet tmpHistContainer = document.getElementById('DataCloner-Throughput-Histogram');\n\t\tif (!tmpHistContainer) return;\n\n\t\tif (!pSamples || pSamples.length < 2)\n\t\t{\n\t\t\ttmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// --- Step 1: Compute raw deltas per 10s interval ---\n\t\tlet tmpRawDeltas = [];\n\t\tfor (let i = 1; i < pSamples.length; i++)\n\t\t{\n\t\t\tlet tmpDelta = pSamples[i].synced - pSamples[i - 1].synced;\n\t\t\tif (tmpDelta < 0) tmpDelta = 0;\n\t\t\ttmpRawDeltas.push({ delta: tmpDelta, t: pSamples[i].t });\n\t\t}\n\n\t\t// --- Step 2: Downsample if there are too many bars ---\n\t\tlet tmpContainerWidth = tmpHistContainer.clientWidth || 800;\n\t\tlet tmpMaxBars = Math.max(20, Math.floor(tmpContainerWidth / 6));\n\t\tlet tmpAggregated = tmpRawDeltas;\n\n\t\tif (tmpRawDeltas.length > tmpMaxBars)\n\t\t{\n\t\t\tlet tmpBucketSize = Math.ceil(tmpRawDeltas.length / tmpMaxBars);\n\t\t\ttmpAggregated = [];\n\t\t\tfor (let i = 0; i < tmpRawDeltas.length; i += tmpBucketSize)\n\t\t\t{\n\t\t\t\tlet tmpSum = 0;\n\t\t\t\tlet tmpLastT = 0;\n\t\t\t\tfor (let j = i; j < Math.min(i + tmpBucketSize, tmpRawDeltas.length); j++)\n\t\t\t\t{\n\t\t\t\t\ttmpSum += tmpRawDeltas[j].delta;\n\t\t\t\t\ttmpLastT = tmpRawDeltas[j].t;\n\t\t\t\t}\n\t\t\t\ttmpAggregated.push({ delta: tmpSum, t: tmpLastT });\n\t\t\t}\n\t\t}\n\n\t\t// --- Step 3: Check for data ---\n\t\tlet tmpHasData = false;\n\t\tfor (let i = 0; i < tmpAggregated.length; i++)\n\t\t{\n\t\t\tif (tmpAggregated[i].delta > 0) { tmpHasData = true; break; }\n\t\t}\n\t\tif (!tmpHasData)\n\t\t{\n\t\t\ttmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// --- Step 4: Build bins for the histogram library ---\n\t\tlet tmpStartT = pSamples[0].t;\n\t\tlet tmpBins = [];\n\t\tfor (let i = 0; i < tmpAggregated.length; i++)\n\t\t{\n\t\t\tlet tmpElapsedSec = Math.round((tmpAggregated[i].t - tmpStartT) / 1000);\n\t\t\ttmpBins.push({\n\t\t\t\tLabel: this.formatElapsed(tmpElapsedSec),\n\t\t\t\tValue: tmpAggregated[i].delta\n\t\t\t});\n\t\t}\n\n\t\t// --- Step 5: Update the histogram view via the library ---\n\t\ttmpHistContainer.style.display = '';\n\t\tlet tmpHistView = this.pict.views['DataCloner-StatusHistogram'];\n\t\tif (tmpHistView)\n\t\t{\n\t\t\ttmpHistView.setBins(tmpBins);\n\t\t\ttmpHistView.renderHistogram();\n\t\t}\n\t}\n\n\tformatElapsed(pSec)\n\t{\n\t\tif (pSec < 60) return pSec + 's';\n\t\tif (pSec < 3600)\n\t\t{\n\t\t\tlet tmpM = Math.floor(pSec / 60);\n\t\t\tlet tmpS = pSec % 60;\n\t\t\treturn tmpM + ':' + (tmpS < 10 ? '0' : '') + tmpS;\n\t\t}\n\t\tlet tmpH = Math.floor(pSec / 3600);\n\t\tlet tmpM = Math.floor((pSec % 3600) / 60);\n\t\treturn tmpH + 'h' + (tmpM < 10 ? '0' : '') + tmpM;\n\t}\n\n\tformatCompact(pNum)\n\t{\n\t\tif (pNum >= 1000000) return (pNum / 1000000).toFixed(1) + 'M';\n\t\tif (pNum >= 10000) return (pNum / 1000).toFixed(0) + 'K';\n\t\tif (pNum >= 1000) return (pNum / 1000).toFixed(1) + 'K';\n\t\treturn pNum.toString();\n\t}\n\n\tformatNumber(pNum)\n\t{\n\t\treturn pNum.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t}\n\n\trenderCompletedRow(pOp)\n\t{\n\t\tlet tmpNew = pOp.Data.New || 0;\n\t\tlet tmpUpdated = pOp.Data.Updated || 0;\n\t\tlet tmpUnchanged = pOp.Data.Unchanged || 0;\n\t\tlet tmpDeleted = pOp.Data.Deleted || 0;\n\t\tlet tmpServerTotal = pOp.Data.ServerTotal || 0;\n\n\t\t// Grand total for the ratio bar: all records the adapter dealt with\n\t\tlet tmpGrandTotal = tmpUnchanged + tmpNew + tmpUpdated + tmpDeleted;\n\t\tif (tmpGrandTotal === 0 && tmpServerTotal > 0)\n\t\t{\n\t\t\ttmpGrandTotal = tmpServerTotal;\n\t\t\ttmpUnchanged = tmpServerTotal;\n\t\t}\n\n\t\tlet tmpHtml = '<div class=\"completed-op-row\">';\n\t\ttmpHtml += '<div class=\"completed-op-header\">';\n\t\ttmpHtml += ' <span class=\"completed-op-checkmark\">\\u2713</span>';\n\t\ttmpHtml += ' <span class=\"completed-op-name\">' + this.escapeHtml(pOp.Name) + '</span>';\n\t\ttmpHtml += '</div>';\n\n\t\t// Ratio bar: Unchanged / New / Updated / Deleted\n\t\tif (tmpGrandTotal > 0)\n\t\t{\n\t\t\tlet tmpUnchangedPct = Math.round((tmpUnchanged / tmpGrandTotal) * 100);\n\t\t\tlet tmpNewPct = Math.round((tmpNew / tmpGrandTotal) * 100);\n\t\t\tlet tmpUpdatedPct = Math.round((tmpUpdated / tmpGrandTotal) * 100);\n\t\t\tlet tmpDeletedPct = Math.round((tmpDeleted / tmpGrandTotal) * 100);\n\n\t\t\t// Ensure percentages sum to 100\n\t\t\tlet tmpPctSum = tmpUnchangedPct + tmpNewPct + tmpUpdatedPct + tmpDeletedPct;\n\t\t\tif (tmpPctSum !== 100 && tmpPctSum > 0)\n\t\t\t{\n\t\t\t\ttmpUnchangedPct += (100 - tmpPctSum);\n\t\t\t\tif (tmpUnchangedPct < 0) tmpUnchangedPct = 0;\n\t\t\t}\n\n\t\t\ttmpHtml += '<div class=\"ratio-bar-container\">';\n\t\t\tif (tmpUnchangedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment unchanged\" style=\"width:' + tmpUnchangedPct + '%\" title=\"Unchanged: ' + this.formatNumber(tmpUnchanged) + '\"></div>';\n\t\t\tif (tmpNewPct > 0) tmpHtml += '<div class=\"ratio-bar-segment new-records\" style=\"width:' + tmpNewPct + '%\" title=\"New: ' + this.formatNumber(tmpNew) + '\"></div>';\n\t\t\tif (tmpUpdatedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment updated\" style=\"width:' + tmpUpdatedPct + '%\" title=\"Updated: ' + this.formatNumber(tmpUpdated) + '\"></div>';\n\t\t\tif (tmpDeletedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment deleted\" style=\"width:' + tmpDeletedPct + '%\" title=\"Deleted: ' + this.formatNumber(tmpDeleted) + '\"></div>';\n\t\t\ttmpHtml += '</div>';\n\n\t\t\ttmpHtml += '<div class=\"ratio-bar-legend\">';\n\t\t\tif (tmpUnchanged > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot unchanged-dot\"></span> Unchanged (' + this.formatNumber(tmpUnchanged) + ')</span>';\n\t\t\tif (tmpNew > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot new-dot\"></span> New (' + this.formatNumber(tmpNew) + ')</span>';\n\t\t\tif (tmpUpdated > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot updated-dot\"></span> Updated (' + this.formatNumber(tmpUpdated) + ')</span>';\n\t\t\tif (tmpDeleted > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot deleted-dot\"></span> Deleted (' + this.formatNumber(tmpDeleted) + ')</span>';\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\trenderErrorRow(pOp, pEventLog)\n\t{\n\t\tlet tmpSynced = pOp.Data.Synced || 0;\n\t\tlet tmpTotal = pOp.Data.Total || 0;\n\t\tlet tmpSyncedFmt = this.formatNumber(tmpSynced);\n\t\tlet tmpTotalFmt = this.formatNumber(tmpTotal);\n\n\t\tlet tmpHtml = '<div class=\"error-op-row\">';\n\t\ttmpHtml += '<div class=\"error-op-header\">';\n\t\ttmpHtml += ' <span style=\"color:#dc3545\">\\u2717</span>';\n\t\ttmpHtml += ' <span class=\"error-op-name\">' + this.escapeHtml(pOp.Name) + '</span>';\n\t\ttmpHtml += ' <span class=\"error-op-status\">' + pOp.Data.Status + ' \\u2014 ' + tmpSyncedFmt + ' / ' + tmpTotalFmt + '</span>';\n\t\ttmpHtml += '</div>';\n\n\t\tif (pOp.Data.ErrorMessage)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"error-op-message\">' + this.escapeHtml(pOp.Data.ErrorMessage) + '</div>';\n\t\t}\n\n\t\t// Extract relevant log entries from EventLog\n\t\tif (pEventLog && pEventLog.length > 0)\n\t\t{\n\t\t\tlet tmpRelevantLogs = [];\n\t\t\tfor (let j = 0; j < pEventLog.length; j++)\n\t\t\t{\n\t\t\t\tlet tmpLog = pEventLog[j];\n\t\t\t\tif (tmpLog.Data && tmpLog.Data.Table === pOp.Name &&\n\t\t\t\t\t(tmpLog.Type === 'TableError' || tmpLog.Type === 'TablePartial'))\n\t\t\t\t{\n\t\t\t\t\ttmpRelevantLogs.push(tmpLog);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tmpRelevantLogs.length > 0)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"error-op-log-entries\">';\n\t\t\t\tfor (let j = 0; j < tmpRelevantLogs.length; j++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpTimestamp = tmpRelevantLogs[j].Timestamp.replace('T', ' ').replace(/\\.\\d+Z$/, '');\n\t\t\t\t\ttmpHtml += '<div>' + this.escapeHtml(tmpTimestamp + ' ' + tmpRelevantLogs[j].Message) + '</div>';\n\t\t\t\t}\n\t\t\t\ttmpHtml += '</div>';\n\t\t\t}\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\t// ================================================================\n\t// Deployed Tables Persistence\n\t// ================================================================\n\n\tsaveDeployedTables()\n\t{\n\t\tlocalStorage.setItem('dataCloner_deployedTables', JSON.stringify(this.pict.AppData.DataCloner.DeployedTables));\n\t}\n\n\trestoreDeployedTables()\n\t{\n\t\ttry\n\t\t{\n\t\t\tlet tmpRaw = localStorage.getItem('dataCloner_deployedTables');\n\t\t\tif (tmpRaw)\n\t\t\t{\n\t\t\t\tthis.pict.AppData.DataCloner.DeployedTables = JSON.parse(tmpRaw);\n\t\t\t\tthis.pict.views['DataCloner-ViewData'].populateViewTableDropdown();\n\t\t\t}\n\t\t}\n\t\tcatch (pError) { /* ignore */ }\n\t}\n\n\t// ================================================================\n\t// Auto-Process\n\t// ================================================================\n\n\tinitAutoProcess()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/live-status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Phase === 'syncing' || pData.Phase === 'stopping')\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.ServerBusyAtLoad = true;\n\t\t\t\t\ttmpSelf.setSectionPhase(5, 'busy');\n\t\t\t\t\ttmpSelf.pict.views['DataCloner-Sync'].startPolling();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttmpSelf.runAutoProcessChain();\n\t\t\t})\n\t\t\t.catch(function()\n\t\t\t{\n\t\t\t\t// Server unreachable — don't auto-process\n\t\t\t});\n\t}\n\n\trunAutoProcessChain()\n\t{\n\t\tlet tmpSelf = this;\n\t\tlet tmpDelay = 0;\n\t\tlet tmpStepDelay = 2000;\n\n\t\tif (document.getElementById('auto1') && document.getElementById('auto1').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Connection'].connectProvider(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto2') && document.getElementById('auto2').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Session'].goAction(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay + 1500;\n\t\t}\n\t\tif (document.getElementById('auto3') && document.getElementById('auto3').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Schema'].fetchSchema(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto4') && document.getElementById('auto4').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Deploy'].deploySchema(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto5') && document.getElementById('auto5').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Sync'].startSync(); }, tmpDelay);\n\t\t}\n\t}\n}\n\nmodule.exports = DataClonerProvider;\n\nmodule.exports.default_configuration =\n{\n\tProviderIdentifier: 'DataCloner',\n\tAutoInitialize: true,\n\tAutoInitializeOrdinal: 0\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerConnectionView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tonProviderChange()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpProviders = ['SQLite', 'MySQL', 'MSSQL', 'PostgreSQL', 'Solr', 'MongoDB', 'RocksDB', 'Bibliograph'];\n\t\tfor (let i = 0; i < tmpProviders.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById('config' + tmpProviders[i]);\n\t\t\tif (tmpEl)\n\t\t\t{\n\t\t\t\ttmpEl.style.display = (tmpProvider === tmpProviders[i]) ? '' : 'none';\n\t\t\t}\n\t\t}\n\t\tthis.pict.providers.DataCloner.saveField('connProvider');\n\t}\n\n\tgetProviderConfig()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\ttmpConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || 'data/cloned.sqlite';\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpConfig.password = document.getElementById('mysqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mysqlDatabase').value.trim();\n\t\t\ttmpConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpConfig.password = document.getElementById('mssqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mssqlDatabase').value.trim();\n\t\t\ttmpConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;\n\t\t\ttmpConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';\n\t\t\ttmpConfig.password = document.getElementById('postgresqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('postgresqlDatabase').value.trim();\n\t\t\ttmpConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;\n\t\t}\n\t\telse if (tmpProvider === 'Solr')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('solrHost').value.trim() || 'localhost';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('solrPort').value, 10) || 8983;\n\t\t\ttmpConfig.core = document.getElementById('solrCore').value.trim() || 'default';\n\t\t\ttmpConfig.path = document.getElementById('solrPath').value.trim() || '/solr';\n\t\t\ttmpConfig.secure = document.getElementById('solrSecure').checked;\n\t\t}\n\t\telse if (tmpProvider === 'MongoDB')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('mongodbHost').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mongodbPort').value, 10) || 27017;\n\t\t\ttmpConfig.user = document.getElementById('mongodbUser').value.trim();\n\t\t\ttmpConfig.password = document.getElementById('mongodbPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mongodbDatabase').value.trim() || 'test';\n\t\t\ttmpConfig.maxPoolSize = parseInt(document.getElementById('mongodbConnectionLimit').value, 10) || 10;\n\t\t}\n\t\telse if (tmpProvider === 'RocksDB')\n\t\t{\n\t\t\ttmpConfig.RocksDBFolder = document.getElementById('rocksdbFolder').value.trim() || 'data/rocksdb';\n\t\t}\n\t\telse if (tmpProvider === 'Bibliograph')\n\t\t{\n\t\t\ttmpConfig.StorageFolder = document.getElementById('bibliographFolder').value.trim() || 'data/bibliograph';\n\t\t}\n\n\t\treturn { Provider: tmpProvider, Config: tmpConfig };\n\t}\n\n\tconnectProvider()\n\t{\n\t\tlet tmpConnInfo = this.getProviderConfig();\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connecting to ' + tmpConnInfo.Provider + '...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/connection/configure', tmpConnInfo)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connection failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'error');\n\t\t\t\t});\n\t}\n\n\ttestConnection()\n\t{\n\t\tlet tmpConnInfo = this.getProviderConfig();\n\n\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Testing ' + tmpConnInfo.Provider + ' connection...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/connection/test', tmpConnInfo)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Test failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tcheckConnectionStatus()\n\t{\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/connection/status')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Connected)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connected: ' + pData.Provider, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'ok');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t() =>\n\t\t\t\t{\n\t\t\t\t\t/* ignore */\n\t\t\t\t});\n\t}\n}\n\nmodule.exports = DataClonerConnectionView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Connection',\n\tDefaultRenderable: 'DataCloner-Connection',\n\tDefaultDestinationAddress: '#DataCloner-Section-Connection',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Connection',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">1</div>\n\t<div class=\"accordion-card\" id=\"section1\" data-section=\"1\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section1')\">\n\t\t\t<div class=\"accordion-title\">Database Connection</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase1\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview1\">SQLite at data/cloned.sqlite</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Connection'].connectProvider()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto1\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Configure the local database where cloned data will be stored. SQLite is connected by default.</p>\n\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:0 0 200px\">\n\t\t\t\t\t<label for=\"connProvider\">Provider</label>\n\t\t\t\t\t<select id=\"connProvider\" onchange=\"pict.views['DataCloner-Connection'].onProviderChange()\">\n\t\t\t\t\t\t<option value=\"SQLite\" selected>SQLite</option>\n\t\t\t\t\t\t<option value=\"MySQL\">MySQL</option>\n\t\t\t\t\t\t<option value=\"MSSQL\">MSSQL</option>\n\t\t\t\t\t\t<option value=\"PostgreSQL\">PostgreSQL</option>\n\t\t\t\t\t\t<option value=\"Solr\">Solr</option>\n\t\t\t\t\t\t<option value=\"MongoDB\">MongoDB</option>\n\t\t\t\t\t\t<option value=\"RocksDB\">RocksDB</option>\n\t\t\t\t\t\t<option value=\"Bibliograph\">Bibliograph</option>\n\t\t\t\t\t</select>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:1; display:flex; align-items:flex-end; gap:8px\">\n\t\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Connection'].connectProvider()\">Connect</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Connection'].testConnection()\">Test Connection</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- SQLite Config -->\n\t\t\t<div id=\"configSQLite\">\n\t\t\t\t<label for=\"sqliteFilePath\">SQLite File Path</label>\n\t\t\t\t<input type=\"text\" id=\"sqliteFilePath\" placeholder=\"data/cloned.sqlite\" value=\"data/cloned.sqlite\">\n\t\t\t</div>\n\n\t\t\t<!-- MySQL Config -->\n\t\t\t<div id=\"configMySQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mysqlServer\">Server</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mysqlServer\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mysqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mysqlPort\" placeholder=\"3306\" value=\"3306\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mysqlUser\" placeholder=\"root\" value=\"root\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mysqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mysqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mysqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlConnectionLimit\">Connection Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mysqlConnectionLimit\" placeholder=\"20\" value=\"20\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- MSSQL Config -->\n\t\t\t<div id=\"configMSSQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mssqlServer\">Server</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mssqlServer\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mssqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mssqlPort\" placeholder=\"1433\" value=\"1433\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mssqlUser\" placeholder=\"sa\" value=\"sa\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mssqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mssqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mssqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlConnectionLimit\">Connection Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mssqlConnectionLimit\" placeholder=\"20\" value=\"20\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- PostgreSQL Config -->\n\t\t\t<div id=\"configPostgreSQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"postgresqlHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"postgresqlHost\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"postgresqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"postgresqlPort\" placeholder=\"5432\" value=\"5432\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"postgresqlUser\" placeholder=\"postgres\" value=\"postgres\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"postgresqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"postgresqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"postgresqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlConnectionLimit\">Connection Pool Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"postgresqlConnectionLimit\" placeholder=\"10\" value=\"10\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- Solr Config -->\n\t\t\t<div id=\"configSolr\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"solrHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrHost\" placeholder=\"localhost\" value=\"localhost\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"solrPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"solrPort\" placeholder=\"8983\" value=\"8983\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"solrCore\">Core</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrCore\" placeholder=\"default\" value=\"default\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"solrPath\">Path</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrPath\" placeholder=\"/solr\" value=\"/solr\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t\t<input type=\"checkbox\" id=\"solrSecure\">\n\t\t\t\t\t<label for=\"solrSecure\">Use HTTPS</label>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- MongoDB Config -->\n\t\t\t<div id=\"configMongoDB\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mongodbHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mongodbHost\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mongodbPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mongodbPort\" placeholder=\"27017\" value=\"27017\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mongodbUser\" placeholder=\"(optional)\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mongodbPassword\" placeholder=\"(optional)\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mongodbDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mongodbDatabase\" placeholder=\"test\" value=\"test\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbConnectionLimit\">Max Pool Size</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mongodbConnectionLimit\" placeholder=\"10\" value=\"10\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- RocksDB Config -->\n\t\t\t<div id=\"configRocksDB\" style=\"display:none\">\n\t\t\t\t<label for=\"rocksdbFolder\">RocksDB Folder Path</label>\n\t\t\t\t<input type=\"text\" id=\"rocksdbFolder\" placeholder=\"data/rocksdb\" value=\"data/rocksdb\">\n\t\t\t</div>\n\n\t\t\t<!-- Bibliograph Config -->\n\t\t\t<div id=\"configBibliograph\" style=\"display:none\">\n\t\t\t\t<label for=\"bibliographFolder\">Storage Folder Path</label>\n\t\t\t\t<input type=\"text\" id=\"bibliographFolder\" placeholder=\"data/bibliograph\" value=\"data/bibliograph\">\n\t\t\t</div>\n\n\t\t\t<div id=\"connectionStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Connection',\n\t\t\tTemplateHash: 'DataCloner-Connection',\n\t\t\tDestinationAddress: '#DataCloner-Section-Connection'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerDeployView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tdeploySchema()\n\t{\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\n\t\tif (tmpSelectedTables.length === 0)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'No tables selected. Fetch a schema and select tables first.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(4, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'Deploying ' + tmpSelectedTables.length + ' tables...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/deploy', { Tables: tmpSelectedTables })\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', pData.Message, 'ok');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'ok');\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.DeployedTables = pData.TablesDeployed || tmpSelectedTables;\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.saveDeployedTables();\n\t\t\t\t\ttmpSelf.pict.views['DataCloner-ViewData'].populateViewTableDropdown();\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.updateAllPreviews();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Deploy failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\t});\n\t}\n\n\tresetDatabase()\n\t{\n\t\tif (!confirm('This will delete ALL data in the local SQLite database. Continue?'))\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'Resetting database...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/reset')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', pData.Message, 'ok');\n\t\t\t\t\t// Clear the sync progress display\n\t\t\t\t\tlet tmpSyncProgress = document.getElementById('syncProgress');\n\t\t\t\t\tif (tmpSyncProgress) tmpSyncProgress.innerHTML = '';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Reset failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n}\n\nmodule.exports = DataClonerDeployView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Deploy',\n\tDefaultRenderable: 'DataCloner-Deploy',\n\tDefaultDestinationAddress: '#DataCloner-Section-Deploy',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Deploy',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">4</div>\n\t<div class=\"accordion-card\" id=\"section4\" data-section=\"4\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section4')\">\n\t\t\t<div class=\"accordion-title\">Deploy Schema</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase4\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview4\">Create selected tables in the local database</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Deploy'].deploySchema()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto4\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Creates the selected tables in the local database and sets up CRUD endpoints (e.g. GET /1.0/Documents).</p>\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Deploy'].deploySchema()\">Deploy Selected Tables</button>\n\t\t\t<button class=\"danger\" onclick=\"pict.views['DataCloner-Deploy'].resetDatabase()\">Reset Database</button>\n\t\t\t<div id=\"deployStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Deploy',\n\t\t\tTemplateHash: 'DataCloner-Deploy',\n\t\t\tDestinationAddress: '#DataCloner-Section-Deploy'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerExportView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tbuildConfigObject()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\t// ---- Local Database ----\n\t\ttmpConfig.LocalDatabase = { Provider: tmpProvider, Config: {} };\n\t\tlet tmpDbConfig = tmpConfig.LocalDatabase.Config;\n\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\ttmpDbConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || 'data/cloned.sqlite';\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpDbConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpDbConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpDbConfig.password = document.getElementById('mysqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('mysqlDatabase').value.trim();\n\t\t\ttmpDbConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpDbConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpDbConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpDbConfig.password = document.getElementById('mssqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('mssqlDatabase').value.trim();\n\t\t\ttmpDbConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\ttmpDbConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;\n\t\t\ttmpDbConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';\n\t\t\ttmpDbConfig.password = document.getElementById('postgresqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('postgresqlDatabase').value.trim();\n\t\t\ttmpDbConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;\n\t\t}\n\n\t\t// ---- Remote Session ----\n\t\ttmpConfig.RemoteSession = {};\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\tif (tmpServerURL) tmpConfig.RemoteSession.ServerURL = tmpServerURL + '/1.0/';\n\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim();\n\t\tif (tmpAuthMethod) tmpConfig.RemoteSession.AuthenticationMethod = tmpAuthMethod;\n\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI) tmpConfig.RemoteSession.AuthenticationURITemplate = tmpAuthURI;\n\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI) tmpConfig.RemoteSession.CheckSessionURITemplate = tmpCheckURI;\n\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\tif (tmpCookieName) tmpConfig.RemoteSession.CookieName = tmpCookieName;\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr) tmpConfig.RemoteSession.CookieValueAddress = tmpCookieValueAddr;\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate) tmpConfig.RemoteSession.CookieValueTemplate = tmpCookieValueTemplate;\n\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\tif (tmpLoginMarker) tmpConfig.RemoteSession.CheckSessionLoginMarker = tmpLoginMarker;\n\n\t\t// ---- Credentials ----\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value;\n\t\tif (tmpUserName || tmpPassword)\n\t\t{\n\t\t\ttmpConfig.Credentials = {};\n\t\t\tif (tmpUserName) tmpConfig.Credentials.UserName = tmpUserName;\n\t\t\tif (tmpPassword) tmpConfig.Credentials.Password = tmpPassword;\n\t\t}\n\n\t\t// ---- Schema ----\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tif (tmpSchemaURL) tmpConfig.SchemaURL = tmpSchemaURL;\n\n\t\t// ---- Tables ----\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\tif (tmpSelectedTables.length > 0) tmpConfig.Tables = tmpSelectedTables;\n\n\t\t// ---- Sync Options ----\n\t\ttmpConfig.Sync = {};\n\t\ttmpConfig.Sync.Mode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\ttmpConfig.Sync.PageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\ttmpConfig.Sync.SyncDeletedRecords = document.getElementById('syncDeletedRecords').checked;\n\t\tlet tmpPrecision = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (!isNaN(tmpPrecision) && tmpPrecision !== 1000) tmpConfig.Sync.DateTimePrecisionMS = tmpPrecision;\n\t\tlet tmpMaxRecords = parseInt(document.getElementById('syncMaxRecords').value, 10);\n\t\tif (tmpMaxRecords > 0) tmpConfig.Sync.MaxRecords = tmpMaxRecords;\n\t\tif (document.getElementById('syncAdvancedIDPagination').checked) tmpConfig.Sync.UseAdvancedIDPagination = true;\n\n\t\treturn tmpConfig;\n\t}\n\n\tbuildMeadowIntegrationConfig()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\t// ---- Source ----\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\ttmpConfig.Source = { ServerURL: tmpServerURL ? tmpServerURL + '/1.0/' : 'https://localhost:8080/1.0/' };\n\t\t// When SessionManager handles auth, Source credentials are not needed\n\t\ttmpConfig.Source.UserID = false;\n\t\ttmpConfig.Source.Password = false;\n\n\t\t// ---- Destination ----\n\t\t// meadow-integration clone supports MySQL and MSSQL\n\t\ttmpConfig.Destination = {};\n\t\tif (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpConfig.Destination.Provider = 'MySQL';\n\t\t\ttmpConfig.Destination.MySQL = {};\n\t\t\ttmpConfig.Destination.MySQL.server = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.Destination.MySQL.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpConfig.Destination.MySQL.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpConfig.Destination.MySQL.password = document.getElementById('mysqlPassword').value || '';\n\t\t\ttmpConfig.Destination.MySQL.database = document.getElementById('mysqlDatabase').value.trim() || 'meadow';\n\t\t\ttmpConfig.Destination.MySQL.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpConfig.Destination.Provider = 'MSSQL';\n\t\t\ttmpConfig.Destination.MSSQL = {};\n\t\t\ttmpConfig.Destination.MSSQL.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.Destination.MSSQL.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpConfig.Destination.MSSQL.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpConfig.Destination.MSSQL.password = document.getElementById('mssqlPassword').value || '';\n\t\t\ttmpConfig.Destination.MSSQL.database = document.getElementById('mssqlDatabase').value.trim() || 'meadow';\n\t\t\ttmpConfig.Destination.MSSQL.ConnectionPoolLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Default to MySQL placeholder for unsupported providers\n\t\t\ttmpConfig.Destination.Provider = 'MySQL';\n\t\t\ttmpConfig.Destination.MySQL = { server: '127.0.0.1', port: 3306, user: 'root', password: '', database: 'meadow', connectionLimit: 20 };\n\t\t}\n\n\t\t// ---- Schema ----\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tif (tmpSchemaURL)\n\t\t{\n\t\t\ttmpConfig.SchemaURL = tmpSchemaURL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpConfig.SchemaPath = './schema/Model-Extended.json';\n\t\t}\n\n\t\t// ---- Sync ----\n\t\ttmpConfig.Sync = {};\n\t\ttmpConfig.Sync.DefaultSyncMode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\ttmpConfig.Sync.PageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\tlet tmpMdwintPrecision = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (!isNaN(tmpMdwintPrecision)) tmpConfig.Sync.DateTimePrecisionMS = tmpMdwintPrecision;\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\ttmpConfig.Sync.SyncEntityList = tmpSelectedTables.length > 0 ? tmpSelectedTables : [];\n\t\ttmpConfig.Sync.SyncEntityOptions = {};\n\t\tif (document.getElementById('syncAdvancedIDPagination').checked) tmpConfig.Sync.UseAdvancedIDPagination = true;\n\n\t\t// ---- SessionManager ----\n\t\ttmpConfig.SessionManager = { Sessions: {} };\n\n\t\tlet tmpSessionConfig = {};\n\t\ttmpSessionConfig.Type = 'Cookie';\n\n\t\t// Authentication method\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim() || 'get';\n\t\ttmpSessionConfig.AuthenticationMethod = tmpAuthMethod;\n\n\t\t// Build the authentication URI template\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI)\n\t\t{\n\t\t\t// If the URI is a relative path, prepend the server URL\n\t\t\tif (tmpAuthURI.charAt(0) === '/')\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = (tmpServerURL || '') + tmpAuthURI;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpAuthURI;\n\t\t\t}\n\t\t}\n\t\telse if (tmpServerURL)\n\t\t{\n\t\t\t// Default: Meadow-style GET authentication\n\t\t\tif (tmpAuthMethod === 'post')\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpServerURL + '/1.0/Authenticate';\n\t\t\t\ttmpSessionConfig.AuthenticationRequestBody = {\n\t\t\t\t\tUserName: '{~D:Record.UserName~}',\n\t\t\t\t\tPassword: '{~D:Record.Password~}'\n\t\t\t\t};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpServerURL + '/1.0/Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}';\n\t\t\t}\n\t\t}\n\n\t\t// Check session URI\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI)\n\t\t{\n\t\t\ttmpSessionConfig.CheckSessionURITemplate = tmpCheckURI.charAt(0) === '/' ? (tmpServerURL || '') + tmpCheckURI : tmpCheckURI;\n\t\t}\n\t\telse if (tmpServerURL)\n\t\t{\n\t\t\ttmpSessionConfig.CheckSessionURITemplate = tmpServerURL + '/1.0/CheckSession';\n\t\t}\n\n\t\t// Login marker\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\ttmpSessionConfig.CheckSessionLoginMarkerType = 'boolean';\n\t\ttmpSessionConfig.CheckSessionLoginMarker = tmpLoginMarker || 'LoggedIn';\n\n\t\t// Domain match — extract from server URL for auto-injection\n\t\tif (tmpServerURL)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tlet tmpUrlObj = new URL(tmpServerURL);\n\t\t\t\ttmpSessionConfig.DomainMatch = tmpUrlObj.host;\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\ttmpSessionConfig.DomainMatch = tmpServerURL;\n\t\t\t}\n\t\t}\n\n\t\t// Cookie injection\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\ttmpSessionConfig.CookieName = tmpCookieName || 'SessionID';\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr) tmpSessionConfig.CookieValueAddress = tmpCookieValueAddr;\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate) tmpSessionConfig.CookieValueTemplate = tmpCookieValueTemplate;\n\n\t\t// Credentials\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value;\n\t\ttmpSessionConfig.Credentials = {};\n\t\tif (tmpUserName) tmpSessionConfig.Credentials.UserName = tmpUserName;\n\t\tif (tmpPassword) tmpSessionConfig.Credentials.Password = tmpPassword;\n\n\t\ttmpConfig.SessionManager.Sessions.SourceAPI = tmpSessionConfig;\n\n\t\treturn tmpConfig;\n\t}\n\n\tgenerateConfig()\n\t{\n\t\tlet tmpConfig = this.buildConfigObject();\n\t\tlet tmpJson = JSON.stringify(tmpConfig, null, '\\t');\n\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\ttmpTextarea.value = tmpJson;\n\t\ttmpTextarea.style.display = '';\n\n\t\t// Build CLI flags from export options\n\t\tlet tmpLogFlag = document.getElementById('syncLogFile').checked ? ' --log' : '';\n\t\tlet tmpMaxFlag = '';\n\t\tlet tmpExportMax = parseInt(document.getElementById('syncMaxRecords').value, 10);\n\t\tif (tmpExportMax > 0) tmpMaxFlag = ' --max ' + tmpExportMax;\n\n\t\t// Build CLI command (with config file)\n\t\tlet tmpCliDiv = document.getElementById('cliCommand');\n\t\ttmpCliDiv.style.display = '';\n\t\ttmpCliDiv.querySelector('div').textContent = 'npx retold-data-service-clone --config clone-config.json --run' + tmpLogFlag + tmpMaxFlag;\n\n\t\t// Build one-liner (no config file needed) using --config-json\n\t\tlet tmpOneShotDiv = document.getElementById('cliOneShot');\n\t\ttmpOneShotDiv.style.display = '';\n\t\tlet tmpCompactJSON = JSON.stringify(tmpConfig);\n\t\t// Escape single quotes for shell wrapping\n\t\tlet tmpEscapedJSON = tmpCompactJSON.replace(/'/g, \"'\\\\''\");\n\t\tlet tmpOneShot = \"npx retold-data-service-clone --config-json '\" + tmpEscapedJSON + \"' --run\" + tmpLogFlag + tmpMaxFlag;\n\t\ttmpOneShotDiv.querySelector('div').textContent = tmpOneShot;\n\n\t\t// ---- meadow-integration (mdwint clone) config ----\n\t\tlet tmpMdwintConfig = this.buildMeadowIntegrationConfig();\n\t\tlet tmpMdwintJSON = JSON.stringify(tmpMdwintConfig, null, '\\t');\n\n\t\tlet tmpMdwintDiv = document.getElementById('mdwintExport');\n\t\ttmpMdwintDiv.style.display = '';\n\n\t\tlet tmpMdwintTextarea = document.getElementById('mdwintConfigOutput');\n\t\ttmpMdwintTextarea.value = tmpMdwintJSON;\n\n\t\t// Build the mdwint CLI command\n\t\tlet tmpMdwintCLI = 'mdwint clone --schema_path ./schema/Model-Extended.json';\n\t\tlet tmpMdwintCLIDiv = document.getElementById('mdwintCLICommand');\n\t\ttmpMdwintCLIDiv.querySelector('div').textContent = tmpMdwintCLI;\n\n\t\t// Provider compatibility note\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tif (tmpProvider !== 'MySQL' && tmpProvider !== 'MSSQL')\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Note: mdwint clone only supports MySQL and MSSQL destinations. The config defaults to MySQL; update the Destination section for your target database.', 'warn');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', '', '');\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Config generated. Save as clone-config.json or copy the one-liner below.', 'ok');\n\t}\n\n\tcopyConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Generate a config first.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpTextarea.value).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'Config copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyCLI()\n\t{\n\t\tlet tmpCmd = document.getElementById('cliCommand').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'CLI command copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyOneShot()\n\t{\n\t\tlet tmpCmd = document.getElementById('cliOneShot').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'One-liner copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tdownloadConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.generateConfig();\n\t\t}\n\t\tlet tmpBlob = new Blob([tmpTextarea.value], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\ttmpAnchor.download = 'clone-config.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Config downloaded as clone-config.json.', 'ok');\n\t}\n\n\tcopyMdwintConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('mdwintConfigOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Generate a config first.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpTextarea.value).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('mdwintConfigStatus', '.meadow.config.json copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyMdwintCLI()\n\t{\n\t\tlet tmpCmd = document.getElementById('mdwintCLICommand').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'mdwint CLI command copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tdownloadMdwintConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('mdwintConfigOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.generateConfig();\n\t\t}\n\t\tlet tmpBlob = new Blob([tmpTextarea.value], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\ttmpAnchor.download = '.meadow.config.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Config downloaded as .meadow.config.json.', 'ok');\n\t}\n}\n\nmodule.exports = DataClonerExportView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Export',\n\tDefaultRenderable: 'DataCloner-Export',\n\tDefaultDestinationAddress: '#DataCloner-Section-Export',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Export',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">6</div>\n\t<div class=\"accordion-card\" id=\"section6\" data-section=\"6\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section6')\">\n\t\t\t<div class=\"accordion-title\">Export Configuration</div>\n\t\t\t<div class=\"accordion-preview\" id=\"preview6\">Generate JSON config for headless cloning</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Generate a JSON config file from your current settings. Use it to run headless clones from the command line.</p>\n\t\t\t<div style=\"display:flex; gap:8px; margin-bottom:10px\">\n\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Export'].generateConfig()\">Generate Config</button>\n\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].copyConfig()\">Copy to Clipboard</button>\n\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].downloadConfig()\">Download JSON</button>\n\t\t\t</div>\n\t\t\t<div id=\"configExportStatus\"></div>\n\t\t\t<div id=\"cliCommand\" style=\"display:none; margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:4px\">CLI Command <span style=\"color:#888; font-weight:normal\">(with config file)</span></label>\n\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer\" onclick=\"pict.views['DataCloner-Export'].copyCLI()\" title=\"Click to copy\"></div>\n\t\t\t</div>\n\t\t\t<div id=\"cliOneShot\" style=\"display:none; margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:4px\">One-liner <span style=\"color:#888; font-weight:normal\">(no config file needed)</span></label>\n\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer; white-space:pre-wrap\" onclick=\"pict.views['DataCloner-Export'].copyOneShot()\" title=\"Click to copy\"></div>\n\t\t\t</div>\n\t\t\t<textarea id=\"configOutput\" style=\"display:none; width:100%; min-height:300px; font-family:monospace; font-size:0.85em; padding:10px; border:1px solid #ccc; border-radius:4px; background:#fafafa; tab-size:4; resize:vertical\" readonly></textarea>\n\n\t\t\t<div id=\"mdwintExport\" style=\"display:none; margin-top:16px; padding-top:16px; border-top:1px solid #eee\">\n\t\t\t\t<h3 style=\"margin:0 0 8px; font-size:1em\">meadow-integration CLI <span style=\"color:#888; font-weight:normal; font-size:0.85em\">(mdwint clone)</span></h3>\n\t\t\t\t<p style=\"font-size:0.85em; color:#666; margin-bottom:8px\">Save as <code>.meadow.config.json</code> in your project root, then run the command below. Requires a local Meadow extended schema JSON file.</p>\n\t\t\t\t<div style=\"display:flex; gap:8px; margin-bottom:10px\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].copyMdwintConfig()\">Copy Config</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].downloadMdwintConfig()\">Download .meadow.config.json</button>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"mdwintCLICommand\" style=\"margin-bottom:10px\">\n\t\t\t\t\t<label style=\"margin-bottom:4px\">CLI Command</label>\n\t\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer\" onclick=\"pict.views['DataCloner-Export'].copyMdwintCLI()\" title=\"Click to copy\"></div>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"mdwintConfigStatus\"></div>\n\t\t\t\t<textarea id=\"mdwintConfigOutput\" style=\"width:100%; min-height:250px; font-family:monospace; font-size:0.85em; padding:10px; border:1px solid #ccc; border-radius:4px; background:#fafafa; tab-size:4; resize:vertical\" readonly></textarea>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Export',\n\t\t\tTemplateHash: 'DataCloner-Export',\n\t\t\tDestinationAddress: '#DataCloner-Section-Export'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerLayoutView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tonAfterRender()\n\t{\n\t\t// Render all section views into their containers\n\t\tthis.pict.views['DataCloner-Connection'].render();\n\t\tthis.pict.views['DataCloner-Session'].render();\n\t\tthis.pict.views['DataCloner-Schema'].render();\n\t\tthis.pict.views['DataCloner-Deploy'].render();\n\t\tthis.pict.views['DataCloner-Sync'].render();\n\t\tthis.pict.views['DataCloner-Export'].render();\n\t\tthis.pict.views['DataCloner-ViewData'].render();\n\n\t\tthis.pict.CSSMap.injectCSS();\n\t}\n\n\ttoggleSection(pSectionId)\n\t{\n\t\tlet tmpCard = document.getElementById(pSectionId);\n\t\tif (!tmpCard) return;\n\t\ttmpCard.classList.toggle('open');\n\t}\n\n\texpandAllSections()\n\t{\n\t\tlet tmpCards = document.querySelectorAll('.accordion-card');\n\t\tfor (let i = 0; i < tmpCards.length; i++)\n\t\t{\n\t\t\ttmpCards[i].classList.add('open');\n\t\t}\n\t}\n\n\tcollapseAllSections()\n\t{\n\t\tlet tmpCards = document.querySelectorAll('.accordion-card');\n\t\tfor (let i = 0; i < tmpCards.length; i++)\n\t\t{\n\t\t\ttmpCards[i].classList.remove('open');\n\t\t}\n\t}\n\n\ttoggleStatusDetail()\n\t{\n\t\tlet tmpDetail = document.getElementById('liveStatusDetail');\n\t\tlet tmpMeta = document.getElementById('liveStatusMeta');\n\t\tlet tmpMessage = document.getElementById('liveStatusMessage');\n\t\tlet tmpToggle = document.getElementById('liveStatusToggle');\n\t\tlet tmpBar = document.getElementById('liveStatusBar');\n\t\tif (!tmpDetail) return;\n\n\t\tlet tmpIsExpanded = tmpDetail.style.display !== 'none';\n\n\t\tif (tmpIsExpanded)\n\t\t{\n\t\t\ttmpDetail.style.display = 'none';\n\t\t\ttmpMeta.style.display = '';\n\t\t\ttmpMessage.style.display = '';\n\t\t\ttmpToggle.innerHTML = '▼';\n\t\t\ttmpBar.classList.remove('expanded');\n\t\t\tthis.pict.providers.DataCloner.onStatusDetailCollapsed();\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpDetail.style.display = '';\n\t\t\ttmpMeta.style.display = 'none';\n\t\t\ttmpMessage.style.display = 'none';\n\t\t\ttmpToggle.innerHTML = '▲';\n\t\t\ttmpBar.classList.add('expanded');\n\t\t\tthis.pict.providers.DataCloner.onStatusDetailExpanded();\n\t\t}\n\t}\n}\n\nmodule.exports = DataClonerLayoutView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Layout',\n\tDefaultRenderable: 'DataCloner-Layout',\n\tDefaultDestinationAddress: '#DataCloner-Application-Container',\n\tCSS: /*css*/`\n* { box-sizing: border-box; margin: 0; padding: 0; }\nbody { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; color: #333; padding: 20px; }\nh1 { margin-bottom: 20px; color: #1a1a1a; }\nh2 { margin-bottom: 12px; color: #444; font-size: 1.2em; border-bottom: 2px solid #ddd; padding-bottom: 6px; }\n\n.section { background: #fff; border-radius: 8px; padding: 20px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n\n/* Accordion layout */\n.accordion-row { display: flex; gap: 0; margin-bottom: 16px; align-items: stretch; }\n.accordion-number {\n\tflex: 0 0 48px; display: flex; align-items: flex-start; justify-content: center;\n\tpadding-top: 16px; font-size: 1.6em; font-weight: 700; color: #4a90d9;\n\tuser-select: none;\n}\n.accordion-card {\n\tflex: 1; background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n\toverflow: hidden; min-width: 0;\n}\n.accordion-header {\n\tdisplay: flex; align-items: center; padding: 14px 20px; cursor: pointer;\n\tuser-select: none; gap: 12px; transition: background 0.15s; line-height: 1.4;\n}\n.accordion-header:hover { background: #fafafa; }\n.accordion-title { font-weight: 600; color: #333; font-size: 1.05em; white-space: nowrap; }\n.accordion-preview { flex: 1; font-style: italic; color: #888; font-size: 0.9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }\n.accordion-toggle {\n\tflex: 0 0 20px; display: flex; align-items: center; justify-content: center;\n\tborder-radius: 4px; transition: background 0.15s, transform 0.25s; font-size: 0.7em; color: #888;\n}\n.accordion-header:hover .accordion-toggle { background: #eee; color: #555; }\n.accordion-card.open .accordion-toggle { transform: rotate(180deg); }\n.accordion-body { padding: 0 20px 20px; display: none; }\n.accordion-card.open .accordion-body { display: block; }\n.accordion-card.open .accordion-header { border-bottom: 1px solid #eee; }\n.accordion-card.open .accordion-preview { display: none; }\n\n/* Action controls (go link + auto checkbox) */\n.accordion-actions { display: flex; align-items: baseline; gap: 8px; flex-shrink: 0; }\n.accordion-card.open .accordion-actions { display: none; }\n.accordion-go {\n\tfont-size: 0.82em; color: #4a90d9; cursor: pointer; text-decoration: none;\n\tfont-weight: 500; white-space: nowrap; padding: 2px 6px; border-radius: 3px;\n\ttransition: background 0.15s;\n}\n.accordion-go:hover { background: #e8f0fe; text-decoration: underline; }\n.accordion-auto {\n\tfont-size: 0.82em; color: #999; white-space: nowrap; cursor: pointer;\n}\n.accordion-auto .auto-label { display: none; }\n.accordion-auto:hover .auto-label { display: inline; }\n.accordion-auto input[type=\"checkbox\"] { width: auto; margin: 0; cursor: pointer; vertical-align: middle; position: relative; top: 0px; opacity: 0.75; transition: opacity 0.15s; }\n.accordion-auto:hover input[type=\"checkbox\"] { opacity: 1; }\n.accordion-auto:hover { color: #666; }\n\n/* Phase status indicator */\n.accordion-phase {\n\tflex: 0 0 auto; display: none; align-items: center; justify-content: center;\n\tfont-size: 0.85em; line-height: 1;\n}\n.accordion-phase.visible { display: flex; }\n.accordion-phase-ok { color: #28a745; }\n.accordion-phase-error { color: #dc3545; }\n.accordion-phase-busy { color: #28a745; }\n.accordion-phase-busy .phase-spinner {\n\tdisplay: inline-block; width: 14px; height: 14px;\n\tborder: 2px solid #28a745; border-top-color: transparent; border-radius: 50%;\n\tanimation: phase-spin 0.8s linear infinite; vertical-align: middle;\n}\n@keyframes phase-spin {\n\tto { transform: rotate(360deg); }\n}\n\n.accordion-controls {\n\tdisplay: flex; gap: 8px; margin-bottom: 12px; justify-content: flex-end;\n}\n.accordion-controls button {\n\tpadding: 4px 10px; font-size: 0.82em; font-weight: 500; background: none;\n\tborder: 1px solid #ccc; border-radius: 4px; color: #666; cursor: pointer; margin: 0;\n}\n.accordion-controls button:hover { background: #f0f0f0; border-color: #aaa; color: #333; }\n\nlabel { display: block; font-weight: 600; margin-bottom: 4px; font-size: 0.9em; }\ninput[type=\"text\"], input[type=\"password\"], input[type=\"number\"] {\n\twidth: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px;\n\tfont-size: 0.95em; margin-bottom: 10px;\n}\ninput[type=\"text\"]:focus, input[type=\"password\"]:focus, input[type=\"number\"]:focus {\n\toutline: none; border-color: #4a90d9;\n}\n\nbutton {\n\tpadding: 8px 16px; border: none; border-radius: 4px; cursor: pointer;\n\tfont-size: 0.9em; font-weight: 600; margin-right: 8px; margin-bottom: 8px;\n}\nbutton.primary { background: #4a90d9; color: #fff; }\nbutton.primary:hover { background: #357abd; }\nbutton.secondary { background: #6c757d; color: #fff; }\nbutton.secondary:hover { background: #5a6268; }\nbutton.danger { background: #dc3545; color: #fff; }\nbutton.danger:hover { background: #c82333; }\nbutton.success { background: #28a745; color: #fff; }\nbutton.success:hover { background: #218838; }\nbutton:disabled { opacity: 0.5; cursor: not-allowed; }\n\n.status { padding: 8px 12px; border-radius: 4px; margin-top: 10px; font-size: 0.9em; }\n.status.ok { background: #d4edda; color: #155724; }\n.status.error { background: #f8d7da; color: #721c24; }\n.status.info { background: #d1ecf1; color: #0c5460; }\n.status.warn { background: #fff3cd; color: #856404; }\n\n.inline-group { display: flex; gap: 8px; align-items: flex-end; margin-bottom: 10px; }\n.inline-group > div { flex: 1; }\n\na { color: #4a90d9; }\n\nselect { background: #fff; width: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 0.95em; margin-bottom: 10px; }\n\n.checkbox-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }\n.checkbox-row input[type=\"checkbox\"] { width: auto; margin: 0; }\n.checkbox-row label { display: inline; margin: 0; font-weight: normal; cursor: pointer; }\n\n/* Live Status Bar */\n.live-status-bar {\n\tbackground: #fff; border-radius: 8px; margin-bottom: 16px;\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.1);\n\tposition: sticky; top: 0; z-index: 100; border-left: 4px solid #6c757d;\n}\n.live-status-bar.phase-idle { border-left-color: #6c757d; }\n.live-status-bar.phase-disconnected { border-left-color: #dc3545; }\n.live-status-bar.phase-ready { border-left-color: #4a90d9; }\n.live-status-bar.phase-syncing { border-left-color: #28a745; }\n.live-status-bar.phase-stopping { border-left-color: #ffc107; }\n.live-status-bar.phase-complete { border-left-color: #28a745; }\n\n.live-status-dot {\n\twidth: 12px; height: 12px; border-radius: 50%; flex-shrink: 0;\n\tbackground: #6c757d;\n}\n.live-status-bar.phase-idle .live-status-dot { background: #6c757d; }\n.live-status-bar.phase-disconnected .live-status-dot { background: #dc3545; }\n.live-status-bar.phase-ready .live-status-dot { background: #4a90d9; }\n.live-status-bar.phase-syncing .live-status-dot {\n\tbackground: #28a745;\n\tanimation: live-pulse 1.5s ease-in-out infinite;\n}\n.live-status-bar.phase-stopping .live-status-dot {\n\tbackground: #ffc107;\n\tanimation: live-pulse 0.8s ease-in-out infinite;\n}\n.live-status-bar.phase-complete .live-status-dot { background: #28a745; }\n\n@keyframes live-pulse {\n\t0%, 100% { opacity: 1; transform: scale(1); }\n\t50% { opacity: 0.4; transform: scale(0.8); }\n}\n\n.live-status-message { flex: 1; font-size: 0.92em; color: #333; line-height: 1.4; }\n\n.live-status-meta {\n\tdisplay: flex; gap: 16px; flex-shrink: 0; font-size: 0.82em; color: #666;\n}\n.live-status-meta-item { white-space: nowrap; }\n.live-status-meta-item strong { color: #333; }\n\n.live-status-progress-bar {\n\theight: 3px; background: #e9ecef; border-radius: 2px; overflow: hidden;\n\tposition: absolute; bottom: 0; left: 0; right: 0;\n}\n.live-status-progress-fill {\n\theight: 100%; background: #28a745; transition: width 1s ease;\n}\n/* Expandable status bar */\n.live-status-header {\n\tdisplay: flex; align-items: center; gap: 14px; cursor: pointer;\n\tpadding: 14px 20px; user-select: none;\n}\n.live-status-bar.expanded .live-status-header {\n\tborder-bottom: 1px solid #e9ecef; padding-bottom: 10px;\n}\n.live-status-expand-toggle {\n\tflex: 0 0 20px; display: flex; align-items: center; justify-content: center;\n\tfont-size: 0.7em; color: #888; transition: transform 0.25s;\n}\n.live-status-bar.expanded .live-status-expand-toggle { transform: rotate(180deg); }\n\n.live-status-detail {\n\tpadding: 12px 20px 16px; max-height: 60vh; overflow-y: auto;\n}\n\n/* Status Detail Sections */\n.status-detail-section { margin-bottom: 14px; }\n.status-detail-section:last-child { margin-bottom: 0; }\n.status-detail-section-title {\n\tfont-size: 0.85em; font-weight: 600; color: #555; text-transform: uppercase;\n\tletter-spacing: 0.5px; margin-bottom: 8px; padding-bottom: 4px;\n\tborder-bottom: 1px solid #eee;\n}\n\n/* Running Operations */\n.running-op-row {\n\tdisplay: flex; align-items: center; gap: 12px; padding: 6px 0;\n\tfont-size: 0.9em;\n}\n.running-op-name { font-weight: 600; min-width: 180px; }\n.running-op-bar {\n\tflex: 1; height: 8px; background: #e9ecef; border-radius: 4px; overflow: hidden;\n\tmin-width: 120px;\n}\n.running-op-bar-fill { height: 100%; background: #4a90d9; transition: width 0.5s ease; }\n.running-op-count { font-size: 0.85em; color: #666; white-space: nowrap; }\n.running-op-pending { color: #888; font-size: 0.85em; font-style: italic; padding: 4px 0; }\n\n/* Completed Operations */\n.completed-op-row { padding: 8px 0; border-bottom: 1px solid #f0f0f0; }\n.completed-op-row:last-child { border-bottom: none; }\n.completed-op-header {\n\tdisplay: flex; align-items: center; gap: 10px; font-size: 0.9em; margin-bottom: 4px;\n}\n.completed-op-name { font-weight: 600; }\n.completed-op-stats { color: #666; font-size: 0.85em; }\n.completed-op-checkmark { color: #28a745; }\n\n/* Ratio Bar */\n.ratio-bar-container {\n\tdisplay: flex; height: 10px; border-radius: 5px; overflow: hidden;\n\tbackground: #e9ecef; margin: 4px 0;\n}\n.ratio-bar-segment { height: 100%; transition: width 0.5s ease; }\n.ratio-bar-segment.unchanged { background: #6c757d; }\n.ratio-bar-segment.new-records { background: #28a745; }\n.ratio-bar-segment.updated { background: #4a90d9; }\n.ratio-bar-segment.deleted { background: #dc3545; }\n.ratio-bar-legend {\n\tdisplay: flex; gap: 12px; font-size: 0.75em; color: #666; margin-top: 2px; flex-wrap: wrap;\n}\n.ratio-bar-legend-item { display: flex; align-items: center; gap: 4px; }\n.ratio-bar-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }\n.ratio-bar-legend-dot.unchanged-dot { background: #6c757d; }\n.ratio-bar-legend-dot.new-dot { background: #28a745; }\n.ratio-bar-legend-dot.updated-dot { background: #4a90d9; }\n.ratio-bar-legend-dot.deleted-dot { background: #dc3545; }\n\n/* Error Operations */\n.error-op-row { padding: 6px 0; border-bottom: 1px solid #f0f0f0; font-size: 0.9em; }\n.error-op-row:last-child { border-bottom: none; }\n.error-op-header { display: flex; align-items: center; gap: 8px; }\n.error-op-name { font-weight: 600; color: #dc3545; }\n.error-op-status { font-size: 0.82em; color: #dc3545; }\n.error-op-message { font-size: 0.82em; color: #888; margin-top: 2px; padding-left: 18px; }\n.error-op-log-entries {\n\tfont-size: 0.78em; color: #888; margin-top: 4px; padding-left: 18px;\n\tfont-family: monospace; max-height: 80px; overflow-y: auto;\n}\n\n/* Pre-count Table */\n.precount-table {\n\twidth: 100%; border-collapse: collapse; font-size: 0.88em;\n}\n.precount-table thead th {\n\ttext-align: left; font-weight: 600; color: #555; font-size: 0.85em;\n\ttext-transform: uppercase; letter-spacing: 0.3px;\n\tpadding: 4px 8px 6px; border-bottom: 2px solid #e9ecef;\n}\n.precount-table tbody td {\n\tpadding: 4px 8px; border-bottom: 1px solid #f0f0f0;\n}\n.precount-table tbody tr:last-child td { border-bottom: 1px solid #e9ecef; }\n.precount-table tfoot td {\n\tpadding: 6px 8px 2px; font-size: 0.95em;\n}\n.precount-error td { color: #dc3545; }\n.precount-pending {\n\tcolor: #888; font-size: 0.85em; font-style: italic; padding: 8px 0 2px;\n\tdisplay: flex; align-items: center; gap: 6px;\n}\n.precount-spinner {\n\tdisplay: inline-block; width: 12px; height: 12px;\n\tborder: 2px solid #ddd; border-top-color: #4a90d9;\n\tborder-radius: 50%; animation: precount-spin 0.8s linear infinite;\n}\n@keyframes precount-spin { to { transform: rotate(360deg); } }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Layout',\n\t\t\tTemplate: /*html*/`\n<h1>Retold Data Cloner</h1>\n\n<!-- Live Status Bar (Expandable) -->\n<div id=\"liveStatusBar\" class=\"live-status-bar phase-idle\" style=\"position:relative\">\n\t<div class=\"live-status-header\" onclick=\"pict.views['DataCloner-Layout'].toggleStatusDetail()\">\n\t\t<div class=\"live-status-dot\"></div>\n\t\t<div class=\"live-status-message\" id=\"liveStatusMessage\">Idle</div>\n\t\t<div class=\"live-status-meta\" id=\"liveStatusMeta\"></div>\n\t\t<div class=\"live-status-expand-toggle\" id=\"liveStatusToggle\">▼</div>\n\t</div>\n\t<div class=\"live-status-detail\" id=\"liveStatusDetail\" style=\"display:none\">\n\t\t<div id=\"DataCloner-Throughput-Histogram\"></div>\n\t\t<div id=\"DataCloner-StatusDetail-Container\"></div>\n\t</div>\n\t<div class=\"live-status-progress-bar\"><div class=\"live-status-progress-fill\" id=\"liveStatusProgressFill\" style=\"width:0%\"></div></div>\n</div>\n\n<!-- Expand / Collapse All -->\n<div class=\"accordion-controls\">\n\t<button onclick=\"pict.views['DataCloner-Layout'].expandAllSections()\">Expand All</button>\n\t<button onclick=\"pict.views['DataCloner-Layout'].collapseAllSections()\">Collapse All</button>\n</div>\n\n<!-- Section containers -->\n<div id=\"DataCloner-Section-Connection\"></div>\n<div id=\"DataCloner-Section-Session\"></div>\n<div id=\"DataCloner-Section-Schema\"></div>\n<div id=\"DataCloner-Section-Deploy\"></div>\n<div id=\"DataCloner-Section-Sync\"></div>\n<div id=\"DataCloner-Section-Export\"></div>\n<div id=\"DataCloner-Section-ViewData\"></div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Layout',\n\t\t\tTemplateHash: 'DataCloner-Layout',\n\t\t\tDestinationAddress: '#DataCloner-Application-Container'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerSchemaView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tfetchSchema()\n\t{\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tlet tmpBody = {};\n\t\tif (tmpSchemaURL)\n\t\t{\n\t\t\ttmpBody.SchemaURL = tmpSchemaURL;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetching schema...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/fetch', tmpBody)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.AppData.DataCloner.FetchedTables = pData.Tables || [];\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetched ' + pData.TableCount + ' tables from ' + pData.SchemaURL, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'ok');\n\t\t\t\t\t\tthis.renderTableList();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetch failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'error');\n\t\t\t\t});\n\t}\n\n\tloadSavedSelections()\n\t{\n\t\ttry\n\t\t{\n\t\t\tlet tmpRaw = localStorage.getItem('dataCloner_selectedTables');\n\t\t\tif (tmpRaw)\n\t\t\t{\n\t\t\t\treturn JSON.parse(tmpRaw);\n\t\t\t}\n\t\t}\n\t\tcatch (pError)\n\t\t{\n\t\t\t/* ignore */\n\t\t}\n\t\treturn null;\n\t}\n\n\tsaveSelections()\n\t{\n\t\tlet tmpSelected = this.getSelectedTables();\n\t\tlocalStorage.setItem('dataCloner_selectedTables', JSON.stringify(tmpSelected));\n\t\tthis.updateSelectionCount();\n\t\tthis.pict.providers.DataCloner.updateAllPreviews();\n\t}\n\n\tupdateSelectionCount()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpCount = this.getSelectedTables().length;\n\t\tlet tmpEl = document.getElementById('tableSelectionCount');\n\t\tif (tmpEl)\n\t\t{\n\t\t\ttmpEl.textContent = tmpCount + ' / ' + tmpFetchedTables.length + ' selected';\n\t\t}\n\t}\n\n\trenderTableList()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpContainer = document.getElementById('tableList');\n\t\ttmpContainer.innerHTML = '';\n\n\t\t// Load previously saved selections; if none, default to none checked\n\t\tlet tmpSaved = this.loadSavedSelections();\n\t\tlet tmpSavedSet = null;\n\t\tif (tmpSaved)\n\t\t{\n\t\t\ttmpSavedSet = {};\n\t\t\tfor (let i = 0; i < tmpSaved.length; i++)\n\t\t\t{\n\t\t\t\ttmpSavedSet[tmpSaved[i]] = true;\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpFetchedTables[i];\n\t\t\tlet tmpDiv = document.createElement('div');\n\t\t\ttmpDiv.className = 'table-item';\n\t\t\ttmpDiv.setAttribute('data-table', tmpName.toLowerCase());\n\n\t\t\tlet tmpCheckbox = document.createElement('input');\n\t\t\ttmpCheckbox.type = 'checkbox';\n\t\t\ttmpCheckbox.id = 'tbl_' + tmpName;\n\t\t\ttmpCheckbox.value = tmpName;\n\t\t\t// If we have saved selections, restore them; otherwise default unchecked\n\t\t\ttmpCheckbox.checked = tmpSavedSet ? (tmpSavedSet[tmpName] === true) : false;\n\t\t\ttmpCheckbox.addEventListener('change', () => { this.saveSelections(); });\n\n\t\t\tlet tmpLabel = document.createElement('label');\n\t\t\ttmpLabel.htmlFor = 'tbl_' + tmpName;\n\t\t\ttmpLabel.textContent = tmpName;\n\n\t\t\ttmpDiv.appendChild(tmpCheckbox);\n\t\t\ttmpDiv.appendChild(tmpLabel);\n\t\t\ttmpContainer.appendChild(tmpDiv);\n\t\t}\n\n\t\tdocument.getElementById('tableSelection').style.display = tmpFetchedTables.length > 0 ? 'block' : 'none';\n\t\tdocument.getElementById('tableFilter').value = '';\n\t\tthis.updateSelectionCount();\n\t}\n\n\tfilterTableList()\n\t{\n\t\tlet tmpFilter = document.getElementById('tableFilter').value.toLowerCase().trim();\n\t\tlet tmpItems = document.getElementById('tableList').children;\n\t\tfor (let i = 0; i < tmpItems.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpItems[i].getAttribute('data-table') || '';\n\t\t\ttmpItems[i].style.display = (!tmpFilter || tmpName.indexOf(tmpFilter) >= 0) ? '' : 'none';\n\t\t}\n\t}\n\n\tselectAllTables(pChecked)\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\t// Only affect visible (non-filtered) items\n\t\tlet tmpFilter = document.getElementById('tableFilter').value.toLowerCase().trim();\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpFetchedTables[i];\n\t\t\tif (tmpFilter && tmpName.toLowerCase().indexOf(tmpFilter) < 0)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet tmpCheckbox = document.getElementById('tbl_' + tmpName);\n\t\t\tif (tmpCheckbox)\n\t\t\t{\n\t\t\t\ttmpCheckbox.checked = pChecked;\n\t\t\t}\n\t\t}\n\t\tthis.saveSelections();\n\t}\n\n\tgetSelectedTables()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpSelected = [];\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpCheckbox = document.getElementById('tbl_' + tmpFetchedTables[i]);\n\t\t\tif (tmpCheckbox && tmpCheckbox.checked)\n\t\t\t{\n\t\t\t\ttmpSelected.push(tmpFetchedTables[i]);\n\t\t\t}\n\t\t}\n\t\treturn tmpSelected;\n\t}\n}\n\nmodule.exports = DataClonerSchemaView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Schema',\n\tDefaultRenderable: 'DataCloner-Schema',\n\tDefaultDestinationAddress: '#DataCloner-Section-Schema',\n\tCSS: /*css*/`\n.table-list { max-height: 300px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 8px; margin: 10px 0; }\n.table-item { padding: 4px 8px; display: flex; align-items: center; }\n.table-item:hover { background: #f0f0f0; }\n.table-item input[type=\"checkbox\"] { margin-right: 8px; width: auto; }\n.table-item label { display: inline; font-weight: normal; margin-bottom: 0; cursor: pointer; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Schema',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">3</div>\n\t<div class=\"accordion-card\" id=\"section3\" data-section=\"3\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section3')\">\n\t\t\t<div class=\"accordion-title\">Remote Schema</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase3\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview3\">Fetch and select tables from the remote server</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Schema'].fetchSchema()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto3\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<label for=\"schemaURL\">Schema URL (leave blank for default: /1.0/Retold/Models)</label>\n\t\t\t<input type=\"text\" id=\"schemaURL\" placeholder=\"http://remote-server:8086/1.0/Retold/Models\">\n\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Schema'].fetchSchema()\">Fetch Schema</button>\n\t\t\t<div id=\"schemaStatus\"></div>\n\n\t\t\t<div id=\"tableSelection\" style=\"display:none\">\n\t\t\t\t<h3 style=\"margin:12px 0 8px; font-size:1em;\">Select Tables</h3>\n\t\t\t\t<div style=\"display:flex; gap:8px; align-items:center; margin-bottom:8px\">\n\t\t\t\t\t<input type=\"text\" id=\"tableFilter\" placeholder=\"Filter tables...\" style=\"flex:1; margin-bottom:0\" oninput=\"pict.views['DataCloner-Schema'].filterTableList()\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Schema'].selectAllTables(true)\" style=\"font-size:0.8em\">Select All</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Schema'].selectAllTables(false)\" style=\"font-size:0.8em\">Deselect All</button>\n\t\t\t\t\t<span id=\"tableSelectionCount\" style=\"font-size:0.85em; color:#666; white-space:nowrap\"></span>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"tableList\" class=\"table-list\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Schema',\n\t\t\tTemplateHash: 'DataCloner-Schema',\n\t\t\tDestinationAddress: '#DataCloner-Section-Schema'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerSessionView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tconfigureSession()\n\t{\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\tif (!tmpServerURL)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Server URL is required.', 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBody = { ServerURL: tmpServerURL.replace(/\\/+$/, '') + '/1.0/' };\n\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim();\n\t\tif (tmpAuthMethod)\n\t\t{\n\t\t\ttmpBody.AuthenticationMethod = tmpAuthMethod;\n\t\t}\n\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI)\n\t\t{\n\t\t\ttmpBody.AuthenticationURITemplate = tmpAuthURI;\n\t\t}\n\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI)\n\t\t{\n\t\t\ttmpBody.CheckSessionURITemplate = tmpCheckURI;\n\t\t}\n\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\tif (tmpCookieName)\n\t\t{\n\t\t\ttmpBody.CookieName = tmpCookieName;\n\t\t}\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr)\n\t\t{\n\t\t\ttmpBody.CookieValueAddress = tmpCookieValueAddr;\n\t\t}\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate)\n\t\t{\n\t\t\ttmpBody.CookieValueTemplate = tmpCookieValueTemplate;\n\t\t}\n\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\tif (tmpLoginMarker)\n\t\t{\n\t\t\ttmpBody.CheckSessionLoginMarker = tmpLoginMarker;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Configuring session...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/configure', tmpBody)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Session configured for ' + pData.ServerURL + ' (domain: ' + pData.DomainMatch + ')', 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Configuration failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tauthenticate()\n\t{\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value.trim();\n\n\t\tif (!tmpUserName || !tmpPassword)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Username and password are required.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authenticating...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/authenticate', { UserName: tmpUserName, Password: tmpPassword })\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success && pData.Authenticated)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authenticated successfully.', 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authentication failed: ' + (pData.Error || 'Not authenticated'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\t\t});\n\t}\n\n\tcheckSession()\n\t{\n\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Checking session...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/session/check')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Authenticated)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session is active. Server: ' + (pData.ServerURL || 'N/A'), 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse if (pData.Configured)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session configured but not authenticated.', 'warn');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'No session configured.', 'warn');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tdeauthenticate()\n\t{\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/deauthenticate')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session deauthenticated.', 'info');\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tgoAction()\n\t{\n\t\t// Two-step: configure session, then authenticate after delay\n\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'busy');\n\t\tthis.configureSession();\n\t\tsetTimeout(\n\t\t\t() =>\n\t\t\t{\n\t\t\t\tthis.authenticate();\n\t\t\t}, 1500);\n\t}\n}\n\nmodule.exports = DataClonerSessionView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Session',\n\tDefaultRenderable: 'DataCloner-Session',\n\tDefaultDestinationAddress: '#DataCloner-Section-Session',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Session',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">2</div>\n\t<div class=\"accordion-card\" id=\"section2\" data-section=\"2\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section2')\">\n\t\t\t<div class=\"accordion-title\">Remote Session</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase2\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview2\">Configure remote server URL and credentials</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Session'].goAction()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto2\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t<label for=\"serverURL\">Remote Server URL</label>\n\t\t\t\t\t<input type=\"text\" id=\"serverURL\" placeholder=\"http://remote-server:8086\" value=\"\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t<label for=\"authMethod\">Auth Method</label>\n\t\t\t\t\t<input type=\"text\" id=\"authMethod\" placeholder=\"get\" value=\"get\">\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<details style=\"margin-bottom:10px\">\n\t\t\t\t<summary style=\"cursor:pointer; font-size:0.9em; color:#666\">Advanced Session Options</summary>\n\t\t\t\t<div style=\"padding:10px 0\">\n\t\t\t\t\t<label for=\"authURI\">Authentication URI Template (leave blank for default)</label>\n\t\t\t\t\t<input type=\"text\" id=\"authURI\" placeholder=\"Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}\">\n\t\t\t\t\t<label for=\"checkURI\">Check Session URI Template</label>\n\t\t\t\t\t<input type=\"text\" id=\"checkURI\" placeholder=\"CheckSession\">\n\t\t\t\t\t<label for=\"cookieName\">Cookie Name</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieName\" placeholder=\"SessionID\" value=\"SessionID\">\n\t\t\t\t\t<label for=\"cookieValueAddr\">Cookie Value Address</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieValueAddr\" placeholder=\"SessionID\" value=\"SessionID\">\n\t\t\t\t\t<label for=\"cookieValueTemplate\">Cookie Value Template (overrides Address if set)</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieValueTemplate\" placeholder=\"{~D:Record.SessionID~}\">\n\t\t\t\t\t<label for=\"loginMarker\">Login Marker</label>\n\t\t\t\t\t<input type=\"text\" id=\"loginMarker\" placeholder=\"LoggedIn\" value=\"LoggedIn\">\n\t\t\t\t</div>\n\t\t\t</details>\n\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Session'].configureSession()\">Configure Session</button>\n\t\t\t<div id=\"sessionConfigStatus\"></div>\n\n\t\t\t<hr style=\"margin:16px 0; border:none; border-top:1px solid #eee\">\n\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div>\n\t\t\t\t\t<label for=\"userName\">Username</label>\n\t\t\t\t\t<input type=\"text\" id=\"userName\" placeholder=\"username\">\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<label for=\"password\">Password</label>\n\t\t\t\t\t<input type=\"password\" id=\"password\" placeholder=\"password\">\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<button class=\"success\" onclick=\"pict.views['DataCloner-Session'].authenticate()\">Authenticate</button>\n\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Session'].checkSession()\">Check Session</button>\n\t\t\t<button class=\"danger\" onclick=\"pict.views['DataCloner-Session'].deauthenticate()\">Deauthenticate</button>\n\t\t\t<div id=\"sessionAuthStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Session',\n\t\t\tTemplateHash: 'DataCloner-Session',\n\t\t\tDestinationAddress: '#DataCloner-Section-Session'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerSyncView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tstartSync()\n\t{\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\tlet tmpPageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\tlet tmpDateTimePrecisionMS = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (isNaN(tmpDateTimePrecisionMS)) tmpDateTimePrecisionMS = 1000;\n\t\tlet tmpSyncDeletedRecords = document.getElementById('syncDeletedRecords').checked;\n\t\tlet tmpSyncMode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\tlet tmpMaxRecords = parseInt(document.getElementById('syncMaxRecords').value, 10) || 0;\n\t\tlet tmpLogToFile = document.getElementById('syncLogFile').checked;\n\t\tlet tmpAdvancedIDPagination = document.getElementById('syncAdvancedIDPagination').checked;\n\n\t\tif (tmpSelectedTables.length === 0)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('syncStatus', 'No tables selected for sync.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(5, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('syncStatus', 'Starting ' + tmpSyncMode.toLowerCase() + ' sync...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tlet tmpPostBody = { Tables: tmpSelectedTables, PageSize: tmpPageSize, DateTimePrecisionMS: tmpDateTimePrecisionMS, SyncDeletedRecords: tmpSyncDeletedRecords, SyncMode: tmpSyncMode };\n\t\tif (tmpMaxRecords > 0) tmpPostBody.MaxRecordsPerEntity = tmpMaxRecords;\n\t\tif (tmpLogToFile) tmpPostBody.LogToFile = true;\n\t\tif (tmpAdvancedIDPagination) tmpPostBody.UseAdvancedIDPagination = true;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/sync/start', tmpPostBody)\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\tlet tmpMsg = pData.SyncMode + ' sync started for ' + pData.Tables.length + ' tables.';\n\t\t\t\t\tif (pData.SyncDeletedRecords) tmpMsg += ' (including deleted records)';\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', tmpMsg, 'ok');\n\t\t\t\t\ttmpSelf.startPolling();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync start failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t});\n\t}\n\n\tstopSync()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/sync/stop')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync stop requested.', 'warn');\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n\n\tstartPolling()\n\t{\n\t\tif (this.pict.AppData.DataCloner.SyncPollTimer) clearInterval(this.pict.AppData.DataCloner.SyncPollTimer);\n\t\tlet tmpSelf = this;\n\t\tthis.pict.AppData.DataCloner.SyncPollTimer = setInterval(function() { tmpSelf.pollSyncStatus(); }, 2000);\n\t\tthis.pollSyncStatus();\n\t}\n\n\tstopPolling()\n\t{\n\t\tif (this.pict.AppData.DataCloner.SyncPollTimer)\n\t\t{\n\t\t\tclearInterval(this.pict.AppData.DataCloner.SyncPollTimer);\n\t\t\tthis.pict.AppData.DataCloner.SyncPollTimer = null;\n\t\t}\n\t}\n\n\tpollSyncStatus()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/sync/status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.renderSyncProgress(pData);\n\n\t\t\t\tif (!pData.Running && !pData.Stopping)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.stopPolling();\n\t\t\t\t\tif (Object.keys(pData.Tables || {}).length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if any tables had errors or partial sync\n\t\t\t\t\t\tlet tmpTables = pData.Tables || {};\n\t\t\t\t\t\tlet tmpHasErrors = false;\n\t\t\t\t\t\tlet tmpHasPartial = false;\n\t\t\t\t\t\tlet tmpNames = Object.keys(tmpTables);\n\t\t\t\t\t\tfor (let i = 0; i < tmpNames.length; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpTables[tmpNames[i]].Status === 'Error') tmpHasErrors = true;\n\t\t\t\t\t\t\tif (tmpTables[tmpNames[i]].Status === 'Partial') tmpHasPartial = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (tmpHasErrors)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync finished with errors. Check the table below for details.', 'error');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (tmpHasPartial)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync finished. Some records were skipped (GUID conflicts or permission issues).', 'warn');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'ok');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync complete.', 'ok');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'ok');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Fetch the structured report\n\t\t\t\t\t\ttmpSelf.fetchSyncReport();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\t// Silently ignore poll errors\n\t\t\t});\n\t}\n\n\tfetchSyncReport()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/sync/report')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData && pData.ReportVersion)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.LastReport = pData;\n\t\t\t\t\ttmpSelf.renderSyncReport(pData);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\t// Ignore report fetch errors\n\t\t\t});\n\t}\n\n\trenderSyncReport(pReport)\n\t{\n\t\tlet tmpSection = document.getElementById('syncReportSection');\n\t\ttmpSection.style.display = '';\n\n\t\t// --- Summary Cards ---\n\t\tlet tmpCardsContainer = document.getElementById('reportSummaryCards');\n\t\tlet tmpOutcomeClass = 'outcome-' + pReport.Outcome.toLowerCase();\n\t\tlet tmpOutcomeColor = { Success: '#28a745', Partial: '#ffc107', Error: '#dc3545', Stopped: '#6c757d' }[pReport.Outcome] || '#666';\n\n\t\tlet tmpDurationSec = pReport.RunTimestamps.DurationSeconds || 0;\n\t\tlet tmpDurationStr = tmpDurationSec < 60 ? tmpDurationSec + 's' : Math.floor(tmpDurationSec / 60) + 'm ' + (tmpDurationSec % 60) + 's';\n\n\t\tlet tmpTotalSynced = pReport.Summary.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\tlet tmpTotalRecords = pReport.Summary.TotalRecords.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\n\t\ttmpCardsContainer.innerHTML = ''\n\t\t\t+ '<div class=\"report-card ' + tmpOutcomeClass + '\">'\n\t\t\t+ ' <div class=\"card-label\">Outcome</div>'\n\t\t\t+ ' <div class=\"card-value\" style=\"color:' + tmpOutcomeColor + '\">' + pReport.Outcome + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Mode</div>'\n\t\t\t+ ' <div class=\"card-value\">' + pReport.Config.SyncMode + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Duration</div>'\n\t\t\t+ ' <div class=\"card-value\">' + tmpDurationStr + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Tables</div>'\n\t\t\t+ ' <div class=\"card-value\">' + pReport.Summary.Complete + ' / ' + pReport.Summary.TotalTables + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Records</div>'\n\t\t\t+ ' <div class=\"card-value\">' + tmpTotalSynced + '</div>'\n\t\t\t+ ' <div style=\"font-size:0.75em; color:#888\">of ' + tmpTotalRecords + '</div>'\n\t\t\t+ '</div>';\n\n\t\t// --- Anomalies ---\n\t\tlet tmpAnomalyContainer = document.getElementById('reportAnomalies');\n\t\tif (pReport.Anomalies.length === 0)\n\t\t{\n\t\t\ttmpAnomalyContainer.innerHTML = '<div style=\"color:#28a745; font-weight:600; font-size:0.9em\">No anomalies detected.</div>';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpHtml = '<h4 style=\"margin:0 0 8px; color:#dc3545; font-size:0.95em\">Anomalies (' + pReport.Anomalies.length + ')</h4>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Type</th><th>Message</th></tr>';\n\t\t\tfor (let i = 0; i < pReport.Anomalies.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpAnomaly = pReport.Anomalies[i];\n\t\t\t\tlet tmpTypeColor = tmpAnomaly.Type === 'Error' ? '#dc3545' : (tmpAnomaly.Type === 'Partial' ? '#ffc107' : '#6c757d');\n\t\t\t\ttmpHtml += '<tr>';\n\t\t\t\ttmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Table) + '</strong></td>';\n\t\t\t\ttmpHtml += '<td style=\"color:' + tmpTypeColor + '\">' + tmpAnomaly.Type + '</td>';\n\t\t\t\ttmpHtml += '<td>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Message) + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\ttmpAnomalyContainer.innerHTML = tmpHtml;\n\t\t}\n\n\t\t// --- Top Tables by Duration ---\n\t\tlet tmpTopContainer = document.getElementById('reportTopTables');\n\t\tlet tmpTopCount = Math.min(10, pReport.Tables.length);\n\t\tif (tmpTopCount > 0)\n\t\t{\n\t\t\tlet tmpHtml = '<h4 style=\"margin:0 0 8px; font-size:0.95em; color:#444\">Top Tables by Duration</h4>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Duration</th><th>Records</th><th>Status</th></tr>';\n\t\t\tfor (let i = 0; i < tmpTopCount; i++)\n\t\t\t{\n\t\t\t\tlet tmpTable = pReport.Tables[i];\n\t\t\t\tlet tmpDur = tmpTable.DurationSeconds < 60 ? tmpTable.DurationSeconds + 's' : Math.floor(tmpTable.DurationSeconds / 60) + 'm ' + (tmpTable.DurationSeconds % 60) + 's';\n\t\t\t\tlet tmpRecs = tmpTable.Total.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\tlet tmpStatusColor = { Complete: '#28a745', Error: '#dc3545', Partial: '#ffc107' }[tmpTable.Status] || '#666';\n\t\t\t\ttmpHtml += '<tr>';\n\t\t\t\ttmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpTable.Name) + '</strong></td>';\n\t\t\t\ttmpHtml += '<td>' + tmpDur + '</td>';\n\t\t\t\ttmpHtml += '<td>' + tmpRecs + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"color:' + tmpStatusColor + '\">' + tmpTable.Status + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\ttmpTopContainer.innerHTML = tmpHtml;\n\t\t}\n\t}\n\n\tdownloadReport()\n\t{\n\t\tif (!this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'No report available.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpJson = JSON.stringify(this.pict.AppData.DataCloner.LastReport, null, '\\t');\n\t\tlet tmpBlob = new Blob([tmpJson], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\tlet tmpTimestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n\t\ttmpAnchor.download = 'DataCloner-Report-' + tmpTimestamp + '.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'Report downloaded.', 'ok');\n\t}\n\n\tcopyReport()\n\t{\n\t\tif (!this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'No report available.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpJson = JSON.stringify(this.pict.AppData.DataCloner.LastReport, null, '\\t');\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpJson).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('reportStatus', 'Report copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\trenderSyncProgress(pData)\n\t{\n\t\tlet tmpContainer = document.getElementById('syncProgress');\n\t\tlet tmpTables = pData.Tables || {};\n\t\tlet tmpTableNames = Object.keys(tmpTables);\n\n\t\tif (tmpTableNames.length === 0)\n\t\t{\n\t\t\ttmpContainer.innerHTML = '';\n\t\t\treturn;\n\t\t}\n\n\t\t// Categorize tables into sections, preserving original order for pending\n\t\tlet tmpSyncing = [];\n\t\tlet tmpPending = [];\n\t\tlet tmpCompleted = [];\n\t\tlet tmpErrors = [];\n\n\t\tfor (let i = 0; i < tmpTableNames.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpTableNames[i];\n\t\t\tlet tmpTable = tmpTables[tmpName];\n\n\t\t\tif (tmpTable.Status === 'Syncing')\n\t\t\t{\n\t\t\t\ttmpSyncing.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse if (tmpTable.Status === 'Pending')\n\t\t\t{\n\t\t\t\ttmpPending.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse if (tmpTable.Status === 'Complete')\n\t\t\t{\n\t\t\t\ttmpCompleted.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Error, Partial, or anything else\n\t\t\t\ttmpErrors.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t}\n\n\t\tlet tmpHtml = '';\n\t\tlet tmpSelf = this;\n\t\tlet fRenderRow = (pName, pTable) =>\n\t\t{\n\t\t\t// Calculate percentage\n\t\t\tlet tmpPct = 0;\n\t\t\tif (pTable.Total === 0 && (pTable.Status === 'Complete' || pTable.Status === 'Error'))\n\t\t\t{\n\t\t\t\ttmpPct = 100;\n\t\t\t}\n\t\t\telse if (pTable.Total > 0)\n\t\t\t{\n\t\t\t\ttmpPct = Math.round((pTable.Synced / pTable.Total) * 100);\n\t\t\t}\n\n\t\t\t// Color the progress bar based on status\n\t\t\tlet tmpBarColor = '#28a745'; // green\n\t\t\tif (pTable.Status === 'Error') tmpBarColor = '#dc3545';\n\t\t\telse if (pTable.Status === 'Partial') tmpBarColor = '#ffc107';\n\t\t\telse if (pTable.Status === 'Syncing') tmpBarColor = '#4a90d9';\n\t\t\telse if (pTable.Status === 'Pending') tmpBarColor = '#adb5bd';\n\n\t\t\t// Status badge\n\t\t\tlet tmpStatusBadge = pTable.Status;\n\t\t\tif (pTable.Status === 'Complete' && pTable.Total === 0) tmpStatusBadge = 'Complete (empty)';\n\t\t\tif (pTable.Status === 'Partial') tmpStatusBadge = 'Partial \\u26A0';\n\t\t\tif (pTable.Status === 'Error') tmpStatusBadge = 'Error \\u2716';\n\n\t\t\t// Details column\n\t\t\tlet tmpDetails = '';\n\t\t\tif (pTable.ErrorMessage) tmpDetails = pTable.ErrorMessage;\n\t\t\telse if (pTable.Skipped > 0) tmpDetails = pTable.Skipped + ' record(s) skipped';\n\t\t\telse if ((pTable.Errors || 0) > 0) tmpDetails = pTable.Errors + ' error(s)';\n\t\t\telse if (pTable.Status === 'Complete' && pTable.Total === 0) tmpDetails = 'No records on server';\n\t\t\telse if (pTable.Status === 'Complete') tmpDetails = '\\u2714 OK';\n\n\t\t\tlet tmpRow = '<tr>';\n\t\t\ttmpRow += '<td><strong>' + pName + '</strong></td>';\n\t\t\ttmpRow += '<td>' + tmpStatusBadge + '</td>';\n\t\t\ttmpRow += '<td>';\n\t\t\ttmpRow += '<div class=\"progress-bar-container\"><div class=\"progress-bar-fill\" style=\"width:' + tmpPct + '%; background:' + tmpBarColor + '\"></div></div>';\n\t\t\ttmpRow += ' ' + tmpPct + '%';\n\t\t\ttmpRow += '</td>';\n\t\t\ttmpRow += '<td>' + pTable.Synced + ' / ' + pTable.Total + '</td>';\n\t\t\ttmpRow += '<td>' + tmpDetails + '</td>';\n\t\t\ttmpRow += '</tr>';\n\t\t\treturn tmpRow;\n\t\t};\n\n\t\t// === SYNCING — currently active ===\n\t\tif (tmpSyncing.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header\">Syncing</div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpSyncing.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpSyncing[i].Name, tmpSyncing[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// === NEXT UP — pending tables in queue order ===\n\t\tif (tmpPending.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header\">Next Up <span class=\"sync-section-count\">' + tmpPending.length + '</span></div>';\n\t\t\t// Show at most 8 upcoming; collapse the rest\n\t\t\tlet tmpShowCount = Math.min(8, tmpPending.length);\n\t\t\ttmpHtml += '<table class=\"progress-table progress-table-muted\">';\n\t\t\tfor (let i = 0; i < tmpShowCount; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += '<tr><td>' + tmpPending[i].Name + '</td>';\n\t\t\t\tif (tmpPending[i].Data.Total > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpHtml += '<td class=\"sync-pending-count\">' + tmpPending[i].Data.Total.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + ' records</td>';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpHtml += '<td class=\"sync-pending-count\">—</td>';\n\t\t\t\t}\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\tif (tmpPending.length > tmpShowCount)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"sync-section-overflow\">+ ' + (tmpPending.length - tmpShowCount) + ' more table' + (tmpPending.length - tmpShowCount === 1 ? '' : 's') + '</div>';\n\t\t\t}\n\t\t}\n\n\t\t// === ERRORS — failed or partial ===\n\t\tif (tmpErrors.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header sync-section-header-error\">Errors <span class=\"sync-section-count\">' + tmpErrors.length + '</span></div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpErrors.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpErrors[i].Name, tmpErrors[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// === COMPLETED — successful tables ===\n\t\tif (tmpCompleted.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header sync-section-header-ok\">Completed <span class=\"sync-section-count\">' + tmpCompleted.length + '</span></div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpCompleted.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpCompleted[i].Name, tmpCompleted[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\t}\n}\n\nmodule.exports = DataClonerSyncView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Sync',\n\tDefaultRenderable: 'DataCloner-Sync',\n\tDefaultDestinationAddress: '#DataCloner-Section-Sync',\n\tCSS: /*css*/`\n.progress-table { width: 100%; border-collapse: collapse; margin-top: 4px; margin-bottom: 4px; }\n.progress-table th, .progress-table td { text-align: left; padding: 6px 12px; border-bottom: 1px solid #eee; font-size: 0.9em; }\n.progress-table th { background: #f8f9fa; font-weight: 600; }\n.progress-table-muted td { color: #888; padding: 3px 12px; font-size: 0.85em; border-bottom: 1px solid #f4f5f6; }\n.progress-bar-container { width: 120px; height: 16px; background: #e9ecef; border-radius: 8px; overflow: hidden; display: inline-block; vertical-align: middle; }\n.progress-bar-fill { height: 100%; background: #28a745; transition: width 0.3s; }\n.sync-section-header { font-size: 0.8em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: #4a90d9; padding: 10px 0 2px 0; margin-top: 6px; border-top: 1px solid #e0e0e0; }\n.sync-section-header:first-child { border-top: none; margin-top: 10px; }\n.sync-section-header-error { color: #dc3545; }\n.sync-section-header-ok { color: #28a745; }\n.sync-section-count { font-weight: 400; color: #999; font-size: 0.95em; }\n.sync-section-overflow { font-size: 0.8em; color: #aaa; padding: 2px 12px 6px; }\n.sync-pending-count { text-align: right; color: #aaa; font-size: 0.85em; }\n.report-card { background: #f8f9fa; border-radius: 8px; padding: 12px 16px; min-width: 140px; text-align: center; border: 1px solid #e9ecef; }\n.report-card .card-label { font-size: 0.8em; color: #666; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }\n.report-card .card-value { font-size: 1.4em; font-weight: 700; }\n.report-card.outcome-success { border-left: 4px solid #28a745; }\n.report-card.outcome-partial { border-left: 4px solid #ffc107; }\n.report-card.outcome-error { border-left: 4px solid #dc3545; }\n.report-card.outcome-stopped { border-left: 4px solid #6c757d; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Sync',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">5</div>\n\t<div class=\"accordion-card\" id=\"section5\" data-section=\"5\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section5')\">\n\t\t\t<div class=\"accordion-title\">Synchronize Data</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase5\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview5\">Initial sync, page size 100</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Sync'].startSync()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto5\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div style=\"display:flex; gap:8px; align-items:flex-end; margin-bottom:4px\">\n\t\t\t\t<div style=\"flex:0 0 150px\">\n\t\t\t\t\t<label for=\"pageSize\">Page Size</label>\n\t\t\t\t\t<input type=\"number\" id=\"pageSize\" value=\"100\" min=\"1\" max=\"10000\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 220px\">\n\t\t\t\t\t<label for=\"dateTimePrecisionMS\">Timestamp Precision (ms)</label>\n\t\t\t\t\t<input type=\"number\" id=\"dateTimePrecisionMS\" value=\"1000\" min=\"0\" max=\"60000\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; gap:8px\">\n\t\t\t\t\t<button class=\"success\" style=\"margin:0\" onclick=\"pict.views['DataCloner-Sync'].startSync()\">Start Sync</button>\n\t\t\t\t\t<button class=\"danger\" style=\"margin:0\" onclick=\"pict.views['DataCloner-Sync'].stopSync()\">Stop Sync</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div style=\"font-size:0.8em; color:#888; margin-bottom:10px; padding-left:158px\">Cross-DB tolerance for date comparison (default: 1000ms)</div>\n\n\t\t\t<div style=\"margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:6px\">Sync Mode</label>\n\t\t\t\t<div style=\"display:flex; gap:16px; align-items:center\">\n\t\t\t\t\t<label style=\"font-weight:normal; margin:0; cursor:pointer\">\n\t\t\t\t\t\t<input type=\"radio\" name=\"syncMode\" id=\"syncModeInitial\" value=\"Initial\" checked> Initial\n\t\t\t\t\t\t<span style=\"color:#888; font-size:0.85em\">(full clone — download all records)</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t<label style=\"font-weight:normal; margin:0; cursor:pointer\">\n\t\t\t\t\t\t<input type=\"radio\" name=\"syncMode\" id=\"syncModeOngoing\" value=\"Ongoing\"> Ongoing\n\t\t\t\t\t\t<span style=\"color:#888; font-size:0.85em\">(delta — only new/updated records since last sync)</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t<input type=\"checkbox\" id=\"syncDeletedRecords\">\n\t\t\t\t<label for=\"syncDeletedRecords\">Sync deleted records (fetch records marked Deleted=1 on source and mirror locally)</label>\n\t\t\t</div>\n\n\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t<input type=\"checkbox\" id=\"syncAdvancedIDPagination\">\n\t\t\t\t<label for=\"syncAdvancedIDPagination\">Use advanced ID pagination (faster for large tables; uses keyset pagination instead of OFFSET)</label>\n\t\t\t</div>\n\n\t\t\t<div class=\"inline-group\" style=\"margin-top:8px; margin-bottom:4px\">\n\t\t\t\t<div style=\"flex:0 0 200px\">\n\t\t\t\t\t<label for=\"syncMaxRecords\">Max Records per Entity</label>\n\t\t\t\t\t<input type=\"number\" id=\"syncMaxRecords\" value=\"\" min=\"0\" placeholder=\"0 = unlimited\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; align-items:flex-end; padding-bottom:2px\">\n\t\t\t\t\t<div class=\"checkbox-row\" style=\"margin-bottom:0\">\n\t\t\t\t\t\t<input type=\"checkbox\" id=\"syncLogFile\" checked>\n\t\t\t\t\t\t<label for=\"syncLogFile\">Write log file</label>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div id=\"syncStatus\"></div>\n\t\t\t<div id=\"syncProgress\"></div>\n\n\t\t\t<!-- Sync Report (appears after sync completes) -->\n\t\t\t<div id=\"syncReportSection\" style=\"display:none; margin-top:16px; padding-top:16px; border-top:2px solid #ddd\">\n\t\t\t\t<h3 style=\"margin:0 0 12px; font-size:1.1em\">Sync Report</h3>\n\n\t\t\t\t<!-- Summary cards -->\n\t\t\t\t<div id=\"reportSummaryCards\" style=\"display:flex; gap:12px; flex-wrap:wrap; margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Anomalies -->\n\t\t\t\t<div id=\"reportAnomalies\" style=\"margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Top tables by duration -->\n\t\t\t\t<div id=\"reportTopTables\" style=\"margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Buttons -->\n\t\t\t\t<div style=\"display:flex; gap:8px\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Sync'].downloadReport()\">Download Report JSON</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Sync'].copyReport()\">Copy Report</button>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"reportStatus\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Sync',\n\t\t\tTemplateHash: 'DataCloner-Sync',\n\t\t\tDestinationAddress: '#DataCloner-Section-Sync'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerViewDataView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tpopulateViewTableDropdown()\n\t{\n\t\tlet tmpSelect = document.getElementById('viewTable');\n\t\tif (!tmpSelect) return;\n\t\tlet tmpCurrentValue = tmpSelect.value;\n\n\t\ttmpSelect.innerHTML = '';\n\n\t\tlet tmpDeployedTables = this.pict.AppData.DataCloner.DeployedTables;\n\n\t\tif (!tmpDeployedTables || tmpDeployedTables.length === 0)\n\t\t{\n\t\t\tlet tmpOpt = document.createElement('option');\n\t\t\ttmpOpt.value = '';\n\t\t\ttmpOpt.textContent = '\\u2014 deploy tables first \\u2014';\n\t\t\ttmpSelect.appendChild(tmpOpt);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = 0; i < tmpDeployedTables.length; i++)\n\t\t{\n\t\t\tlet tmpOpt = document.createElement('option');\n\t\t\ttmpOpt.value = tmpDeployedTables[i];\n\t\t\ttmpOpt.textContent = tmpDeployedTables[i];\n\t\t\ttmpSelect.appendChild(tmpOpt);\n\t\t}\n\n\t\t// Restore previous selection if it exists\n\t\tif (tmpCurrentValue)\n\t\t{\n\t\t\ttmpSelect.value = tmpCurrentValue;\n\t\t}\n\t}\n\n\tloadTableData()\n\t{\n\t\tlet tmpTable = document.getElementById('viewTable').value;\n\t\tlet tmpLimit = parseInt(document.getElementById('viewLimit').value, 10) || 100;\n\n\t\tif (!tmpTable)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('viewStatus', 'Select a table first.', 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('viewStatus', 'Loading ' + tmpTable + '...', 'info');\n\t\tdocument.getElementById('viewDataContainer').innerHTML = '';\n\n\t\tlet tmpSelf = this;\n\t\t// Use the standard Meadow CRUD list endpoint: /1.0/{Entity}s/0/{Cap}\n\t\tthis.pict.providers.DataCloner.api('GET', '/1.0/' + tmpTable + 's/0/' + tmpLimit)\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (!Array.isArray(pData))\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', 'Unexpected response (not an array). The table may not be deployed yet.', 'error');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', pData.length + ' row(s) returned' + (pData.length >= tmpLimit ? ' (limit reached \\u2014 increase Max Rows to see more)' : '') + '.', 'ok');\n\t\t\t\ttmpSelf.renderDataTable(pData);\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n\n\trenderDataTable(pRows)\n\t{\n\t\tlet tmpContainer = document.getElementById('viewDataContainer');\n\n\t\tif (!pRows || pRows.length === 0)\n\t\t{\n\t\t\ttmpContainer.innerHTML = '<p style=\"color:#666; font-size:0.9em; padding:8px\">No rows.</p>';\n\t\t\treturn;\n\t\t}\n\n\t\t// Collect all column names from the first row\n\t\tlet tmpColumns = Object.keys(pRows[0]);\n\n\t\tlet tmpHtml = '<table class=\"data-table\">';\n\t\ttmpHtml += '<thead><tr>';\n\t\tfor (let c = 0; c < tmpColumns.length; c++)\n\t\t{\n\t\t\ttmpHtml += '<th>' + this.pict.providers.DataCloner.escapeHtml(tmpColumns[c]) + '</th>';\n\t\t}\n\t\ttmpHtml += '</tr></thead>';\n\n\t\ttmpHtml += '<tbody>';\n\t\tfor (let r = 0; r < pRows.length; r++)\n\t\t{\n\t\t\ttmpHtml += '<tr>';\n\t\t\tfor (let c = 0; c < tmpColumns.length; c++)\n\t\t\t{\n\t\t\t\tlet tmpVal = pRows[r][tmpColumns[c]];\n\t\t\t\tlet tmpDisplay = (tmpVal === null || tmpVal === undefined) ? '' : String(tmpVal);\n\t\t\t\ttmpHtml += '<td title=\"' + this.pict.providers.DataCloner.escapeHtml(tmpDisplay) + '\">' + this.pict.providers.DataCloner.escapeHtml(tmpDisplay) + '</td>';\n\t\t\t}\n\t\t\ttmpHtml += '</tr>';\n\t\t}\n\t\ttmpHtml += '</tbody></table>';\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\t}\n}\n\nmodule.exports = DataClonerViewDataView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-ViewData',\n\tDefaultRenderable: 'DataCloner-ViewData',\n\tDefaultDestinationAddress: '#DataCloner-Section-ViewData',\n\tCSS: /*css*/`\n.data-table { width: 100%; border-collapse: collapse; font-size: 0.8em; font-family: monospace; }\n.data-table th { background: #f8f9fa; font-weight: 600; text-align: left; padding: 4px 8px; border: 1px solid #ddd; white-space: nowrap; position: sticky; top: 0; }\n.data-table td { padding: 4px 8px; border: 1px solid #eee; white-space: nowrap; max-width: 300px; overflow: hidden; text-overflow: ellipsis; }\n.data-table tr:nth-child(even) { background: #fafafa; }\n.data-table tr:hover { background: #f0f7ff; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-ViewData',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">7</div>\n\t<div class=\"accordion-card\" id=\"section7\" data-section=\"7\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section7')\">\n\t\t\t<div class=\"accordion-title\">View Data</div>\n\t\t\t<div class=\"accordion-preview\" id=\"preview7\">Browse synced table data</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t<label for=\"viewTable\">Table</label>\n\t\t\t\t\t<select id=\"viewTable\">\n\t\t\t\t\t\t<option value=\"\">\\u2014 deploy tables first \\u2014</option>\n\t\t\t\t\t</select>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 120px\">\n\t\t\t\t\t<label for=\"viewLimit\">Max Rows</label>\n\t\t\t\t\t<input type=\"number\" id=\"viewLimit\" value=\"100\" min=\"1\" max=\"10000\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; align-items:flex-end\">\n\t\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-ViewData'].loadTableData()\">Load</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div id=\"viewStatus\"></div>\n\t\t\t<div id=\"viewDataContainer\" style=\"overflow-x:auto; margin-top:10px\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-ViewData',\n\t\t\tTemplateHash: 'DataCloner-ViewData',\n\t\t\tDestinationAddress: '#DataCloner-Section-ViewData'\n\t\t}\n\t]\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["data-cloner.min.js","node_modules/browser-pack/_prelude.js","node_modules/fable-serviceproviderbase/package.json","node_modules/fable-serviceproviderbase/source/Fable-ServiceProviderBase.js","node_modules/pict-application/package.json","node_modules/pict-application/source/Pict-Application.js","node_modules/pict-provider/package.json","node_modules/pict-provider/source/Pict-Provider.js","node_modules/pict-section-histogram/source/Pict-Section-Histogram-DefaultConfiguration.js","node_modules/pict-section-histogram/source/Pict-Section-Histogram.js","node_modules/pict-section-histogram/source/renderers/Pict-Histogram-Renderer-Browser.js","node_modules/pict-section-histogram/source/renderers/Pict-Histogram-Renderer-CLI.js","node_modules/pict-section-histogram/source/renderers/Pict-Histogram-Renderer-ConsoleUI.js","node_modules/pict-view/package.json","node_modules/pict-view/source/Pict-View.js","node_modules/process/browser.js","source/services/data-cloner/pict-app/Pict-Application-DataCloner-Configuration.json","source/services/data-cloner/pict-app/Pict-Application-DataCloner.js","source/services/data-cloner/pict-app/Pict-DataCloner-Bundle.js","source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Deploy.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Schema.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Session.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-Sync.js","source/services/data-cloner/pict-app/views/PictView-DataCloner-ViewData.js"],"names":["f","exports","module","define","amd","window","global","self","this","dataCloner","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","name","version","description","main","scripts","start","test","tests","coverage","build","types","check","mocha","diff","extension","package","reporter","slow","timeout","ui","repository","type","url","keywords","author","license","bugs","homepage","devDependencies","fable","quackage","typescript","libPackage","FableServiceProviderBase","constructor","pFable","pOptions","pServiceHash","UUID","options","services","servicesMap","isFable","connectFable","_PackageFableServiceProvider","getUUID","Math","floor","random","serviceType","Hash","tmpErrorMessage","console","log","Logging","static","CoreServiceProviderBase","lint","eslint","pict","dependencies","libFableServiceBase","defaultPictSettings","Name","MainViewportViewIdentifier","MainViewportRenderableHash","MainViewportDestinationAddress","MainViewportDefaultDataAddress","AutoSolveAfterInitialize","AutoRenderMainViewportViewAfterInitialize","AutoRenderViewsAfterInitialize","AutoLoginAfterInitialize","AutoLoadDataAfterLogin","ConfigurationOnlyViews","Manifests","IdentifierAddressPrefix","tmpCarryOverConfiguration","settings","PictApplicationConfiguration","super","Object","assign","JSON","parse","stringify","_Package","AppData","Bundle","initializeTimestamp","lastSolvedTimestamp","lastLoginTimestamp","lastMarshalFromViewsTimestamp","lastMarshalToViewsTimestamp","lastAutoRenderTimestamp","lastLoadDataTimestamp","tmpManifestKeys","keys","tmpManifestKey","instantiateServiceProvider","onPreSolve","LogNoisiness","trace","onPreSolveAsync","fCallback","onBeforeSolve","onBeforeSolveAsync","onSolve","onSolveAsync","solve","tmpLoadedProviders","providers","tmpProvidersToSolve","tmpProvider","AutoSolveWithApp","push","sort","b","AutoSolveOrdinal","tmpLoadedViews","views","tmpViewsToSolve","tmpView","AutoInitialize","AutoInitializeOrdinal","onAfterSolve","getTimeStamp","solveAsync","tmpAnticipate","instantiateServiceProviderWithoutRegistration","anticipate","bind","tmpCallback","warn","pError","error","onAfterSolveAsync","wait","onBeforeLoginAsync","onLoginAsync","loginAsync","onAfterLoginAsync","fNext","isLoggedIn","loadDataAsync","onBeforeLoadDataAsync","onLoadDataAsync","tmpProvidersToLoadData","AutoLoadDataWithApp","AutoLoadDataOrdinal","onAfterLoadDataAsync","onBeforeSaveDataAsync","onSaveDataAsync","saveDataAsync","tmpProvidersToSaveData","AutoSaveDataWithApp","AutoSaveDataOrdinal","onAfterSaveDataAsync","lastSaveDataTimestamp","onBeforeInitialize","onBeforeInitializeAsync","onInitialize","onInitializeAsync","initialize","LogControlFlow","tmpViewIdentifier","ViewIdentifier","info","addView","tmpProvidersToInitialize","tmpViewsToInitialize","onAfterInitialize","render","onCompletionOfInitialize","initializeAsync","onCompletionOfInitializeAsync","onAfterInitializeAsync","renderMainViewportAsync","message","stack","onBeforeMarshalFromViews","onBeforeMarshalFromViewsAsync","onMarshalFromViews","onMarshalFromViewsAsync","marshalFromViews","tmpViewsToMarshalFromViews","marshalFromView","onAfterMarshalFromViews","marshalFromViewsAsync","marshalFromViewAsync","onAfterMarshalFromViewsAsync","onBeforeMarshalToViews","onBeforeMarshalToViewsAsync","onMarshalToViews","onMarshalToViewsAsync","marshalToViews","tmpViewsToMarshalToViews","marshalToView","onAfterMarshalToViews","marshalToViewsAsync","marshalToViewAsync","onAfterMarshalToViewsAsync","onBeforeRender","onBeforeRenderAsync","pViewIdentifier","pRenderableHash","pRenderDestinationAddress","pTemplateDataAddress","tmpRenderableHash","tmpRenderDestinationAddress","tmpTemplateDataAddress","PictView","onRender","onAfterRender","onRenderAsync","renderAsync","tmpRenderAnticipate","newAnticipate","onAfterRenderAsync","renderMainViewport","renderAutoViews","AutoRenderOrdinal","AutoRender","renderAutoViewsAsync","isPictApplication","defaultPictProviderSettings","ProviderIdentifier","Templates","tmpDefaultTemplate","hasOwnProperty","Source","TemplateProvider","addDefaultTemplate","Prefix","Postfix","Template","Stack","onPreRender","onPreRenderAsync","RenderOnLoad","DefaultRenderable","DefaultDestinationAddress","Renderables","RenderableHash","TemplateHash","DestinationAddress","TargetElementAddress","DataAddress","Bins","LabelProperty","ValueProperty","Orientation","RenderMode","MaxBarSize","BarThickness","BarGap","ShowValues","ShowLabels","BarColor","SelectedBarColor","SelectionRangeColor","Selectable","SelectionMode","SelectionDataAddress","InitialSelection","BarCharacter","BarPartialCharacters","EmptyCharacter","SliderCharacter","SliderHandleCharacter","TextWidth","TextHeight","CSS","libPictViewClass","_DefaultConfiguration","libRendererBrowser","libRendererConsoleUI","libRendererCLI","initialRenderComplete","_selectedIndices","Set","_selectionRangeStart","_selectionRangeEnd","_renderer","_resolveRenderer","_applyInitialSelection","setSelection","tmpBins","getBins","max","_syncSelectionFromRange","tmpAddressSpace","Fable","Pict","Options","tmpData","manifest","getValueByHash","Array","isArray","setBins","pBins","setValueByHash","isIndexSelected","pIndex","has","isIndexInRange","getSelection","tmpIndices","Mode","RangeStart","RangeEnd","SelectedIndices","StartLabel","EndLabel","from","pSelection","Start","End","_writeSelectionToAddress","handleBarClick","clear","add","delete","onSelectionChange","renderHistogram","handleRangeBarClick","abs","min","pRenderable","CSSMap","injectCSS","onAfterInitialRender","wireEvents","setOrientation","pOrientation","setRenderMode","pRenderMode","toText","renderVertical","renderHorizontal","default_configuration","renderers","browser","consoleui","cli","buildBarGroupHTML","pBin","pBarSize","pIsSelected","pInRange","pLabelWidth","tmpLabel","tmpValue","tmpVertical","tmpBarColor","tmpSelectableClass","tmpSelectedClass","tmpInRangeClass","tmpBarStyle","tmpGroupWidth","tmpGroupStyle","tmpHTML","wireRangeHandle","pView","pHandle","pContainer","tmpHandleType","getAttribute","tmpDragging","onPointerMove","pEvent","tmpBounds","tmpSlider","querySelector","size","tmpRect","getBoundingClientRect","left","width","top","height","getSliderBounds","tmpPct","clientX","clientY","tmpIndex","round","onPointerUp","document","removeEventListener","addEventListener","preventDefault","ContentAssignment","assignContent","tmpMaxValue","tmpVal","tmpOrientationClass","tmpLabelWidth","tmpEstWidth","String","tmpBarSize","tmpIsSelected","tmpInRange","tmpRangeStart","tmpRangeEnd","tmpMax","tmpStartPct","tmpEndPct","buildRangeSliderHTML","tmpTargetElementSet","getElement","tmpContainer","tmpBars","querySelectorAll","parseInt","currentTarget","isNaN","tmpHandles","process","ANSI_COLORS","black","red","green","yellow","blue","magenta","cyan","white","reset","bold","dim","colorToAnsi","pColor","tmpLower","toLowerCase","charAt","tmpR","substring","tmpG","tmpB","tmpOptions","tmpHeight","tmpBarChar","tmpPartials","tmpSelectedColor","tmpRangeColor","tmpReset","tmpValueAxisWidth","tmpLines","tmpRow","tmpLine","padLeft","ceil","tmpBarHeight","tmpFullRows","tmpFraction","tmpColor","tmpChar","tmpAxisLine","tmpLabelLine","padCenter","tmpStart","tmpEnd","tmpStartLabel","tmpEndLabel","join","tmpWidth","tmpMaxLabelLen","tmpBarWidth","tmpBarLen","tmpBar","j","padRight","pStr","pLen","tmpStr","tmpText","stdout","write","_process","tmpEmptyChar","tmpRangeLine","tmpFullChars","tmpMarker","tmpValueStr","defaultPictViewSettings","DefaultTemplateRecordAddress","CSSHash","CSSProvider","CSSPriority","DefaultTemplates","tmpHashIsUUID","lastRenderedTimestamp","lastMarshalFromViewTimestamp","lastMarshalToViewTimestamp","instantiateServiceProviderIfNotExists","tmpTemplate","addTemplate","tmpCSSHash","tmpCSSProvider","addCSS","renderables","tmpRenderable","addRenderable","pTemplateHash","pDefaultTemplateRecordAddress","pDefaultDestinationAddress","pRenderMethod","ContentDestinationAddress","RenderMethod","onBeforeProject","onBeforeProjectAsync","buildRenderOptions","pTemplateRecordAddress","tmpRenderOptions","Valid","Renderable","RecordAddress","Record","DataProvider","getDataByAddress","undefined","assignRenderContent","pContent","projectContent","TestAddress","pRootRenderable","renderWithScope","pScope","tmpRecordAddress","tmpRecord","TransactionHash","RootRenderableViewHash","TransactionTracking","registerTransaction","Content","parseTemplateByHash","RootRenderable","onProject","onAfterProject","renderWithScopeAsync","fOnBeforeRenderCallback","fAsyncTemplateCallback","onProjectAsync","onAfterProjectAsync","renderDefaultAsync","basicRender","basicRenderWithScope","basicRenderAsync","basicRenderWithScopeAsync","pushToTransactionQueue","ViewHash","tmpTransactionQueue","clearTransactionQueue","tmpEvent","Data","queue","event","onBeforeMarshalFromView","onBeforeMarshalFromViewAsync","onMarshalFromView","onMarshalFromViewAsync","onAfterMarshalFromView","onAfterMarshalFromViewAsync","onBeforeMarshalToView","onBeforeMarshalToViewAsync","onMarshalToView","onMarshalToViewAsync","onAfterMarshalToView","onAfterMarshalToViewAsync","isPictView","cachedSetTimeout","cachedClearTimeout","defaultSetTimout","defaultClearTimeout","runTimeout","fun","setTimeout","clearTimeout","currentQueue","draining","queueIndex","cleanUpNextTick","concat","drainQueue","len","run","marker","runClearTimeout","Item","array","noop","nextTick","args","arguments","prototype","apply","title","env","argv","versions","on","addListener","once","off","removeListener","removeAllListeners","emit","prependListener","prependOnceListener","listeners","binding","cwd","chdir","dir","umask","pict_configuration","Product","libPictApplication","libProvider","libViewLayout","libViewConnection","libViewSession","libViewSchema","libViewDeploy","libViewSync","libViewExport","libViewViewData","libViewHistogram","addProvider","FillContainer","DataCloner","FetchedTables","DeployedTables","LastReport","ServerBusyAtLoad","SyncPollTimer","LiveStatusTimer","StatusDetailExpanded","StatusDetailAutoExpanded","StatusDetailTimer","StatusDetailData","LastLiveStatus","PersistFields","initPersistence","onProviderChange","restoreDeployedTables","startLiveStatusPolling","initAccordionPreviews","updateAllPreviews","collapseAllSections","initAutoProcess","DataClonerApplication","libPictProvider","api","pMethod","pPath","pBody","tmpOpts","method","headers","body","fetch","then","pResponse","json","setStatus","pElementId","pMessage","pType","tmpEl","getElementById","className","textContent","style","display","escapeHtml","tmpDiv","createElement","appendChild","createTextNode","innerHTML","setSectionPhase","pSection","pState","classList","value","tmpPreview1","tmpServerURL","tmpUserName","tmpPreview2","tmpTableChecks","tmpSchemaURL","tmpDeployedEl","tmpDeployedText","indexOf","tmpSyncMode","tmpSyncPreview","checked","tmpMaxRecords","tmpLogFile","tmpExportParts","tmpViewTable","tmpSelf","tmpPreviewFields","tmpHandler","tmpCheckboxes","forEach","pEl","saveField","pFieldId","localStorage","setItem","restoreFields","tmpPersistFields","tmpId","tmpSaved","getItem","tmpSyncDeleted","tmpSolrSecure","tmpAdvancedIDPagination","pId","tmpSyncDeletedEl","tmpSolrSecureEl","tmpAdvancedIDPaginationEl","tmpAutoIds","tmpAppData","clearInterval","pollLiveStatus","setInterval","pData","renderLiveStatus","catch","Phase","Message","TotalSynced","TotalRecords","tmpMsg","tmpMeta","tmpProgressFill","tmpWasExpanded","contains","tmpMetaParts","Elapsed","ETA","TotalTables","Completed","tmpSynced","toString","replace","PreCountGrandTotal","tmpGrandTotal","PreCountProgress","Counted","tmpCountedSoFar","Errors","tmpTablePct","ActiveProgress","Total","Synced","tmpLayoutView","toggleStatusDetail","renderStatusDetail","pReportData","ReportVersion","onStatusDetailExpanded","pollStatusDetail","onStatusDetailCollapsed","renderCountingPhaseDetail","pPreCountProgress","tmpTables","Tables","tmpCounted","tmpTotal","tmpRunningTotal","tmpHtml","tmpT","Count","tmpCountFmt","formatNumber","tmpTimeFmt","ElapsedMs","toFixed","tmpRemaining","tmpLiveStatus","tmpStatusData","tmpReport","tmpSummaryBanner","buildStatusSummaryHtml","tmpHistContainer","tmpThroughputSamples","tmpEventLog","tmpIsLive","ThroughputSamples","EventLog","tmpRunning","tmpPending","tmpCompleted","tmpErrors","tmpTableNames","tmpName","Status","tmpOp","tmpSyncedFmt","tmpTotalFmt","renderCompletedRow","renderErrorRow","updateThroughputHistogram","pSamples","tmpRawDeltas","tmpDelta","synced","delta","tmpContainerWidth","clientWidth","tmpMaxBars","tmpAggregated","tmpBucketSize","tmpSum","tmpLastT","tmpHasData","tmpStartT","tmpElapsedSec","Label","formatElapsed","Value","tmpHistView","tmpParts","tmpMessage","Outcome","RunTimestamps","DurationSeconds","Summary","TotalErrors","pSec","tmpS","tmpH","tmpM","formatCompact","pNum","pOp","tmpNew","New","tmpUpdated","Updated","tmpUnchanged","Unchanged","tmpDeleted","Deleted","tmpServerTotal","ServerTotal","tmpUnchangedPct","tmpNewPct","tmpUpdatedPct","tmpDeletedPct","tmpPctSum","pEventLog","ErrorMessage","tmpRelevantLogs","tmpLog","Table","Type","tmpTimestamp","Timestamp","saveDeployedTables","tmpRaw","populateViewTableDropdown","startPolling","runAutoProcessChain","tmpDelay","tmpStepDelay","connectProvider","goAction","fetchSchema","deploySchema","startSync","libPictView","tmpProviders","getProviderConfig","tmpConfig","SQLiteFilePath","trim","host","port","user","password","database","connectionLimit","server","core","path","secure","maxPoolSize","RocksDBFolder","StorageFolder","Provider","Config","_connectInFlight","tmpConnInfo","Success","testConnection","checkConnectionStatus","Connected","tmpSelectedTables","getSelectedTables","tmpStatusMsg","MigrationsApplied","map","pM","ColumnsAdded","TablesDeployed","auditGUIDIndices","tmpReportEl","MissingCount","tmpTable","GUIDColumns","tmpCol","tmpStatus","HasIndex","IndexName","Column","createMissingGUIDIndices","IndicesCreated","tmpIdx","resetDatabase","confirm","tmpSyncProgress","buildConfigObject","LocalDatabase","tmpDbConfig","RemoteSession","ServerURL","tmpAuthMethod","AuthenticationMethod","tmpAuthURI","AuthenticationURITemplate","tmpCheckURI","CheckSessionURITemplate","tmpCookieName","CookieName","tmpCookieValueAddr","CookieValueAddress","tmpCookieValueTemplate","CookieValueTemplate","tmpLoginMarker","CheckSessionLoginMarker","tmpPassword","Credentials","UserName","Password","SchemaURL","Sync","PageSize","SyncDeletedRecords","tmpPrecision","DateTimePrecisionMS","MaxRecords","UseAdvancedIDPagination","buildMeadowIntegrationConfig","UserID","Destination","MySQL","MSSQL","ConnectionPoolLimit","SchemaPath","DefaultSyncMode","tmpMdwintPrecision","SyncEntityList","SyncEntityOptions","SessionManager","Sessions","tmpSessionConfig","AuthenticationRequestBody","CheckSessionLoginMarkerType","tmpUrlObj","URL","DomainMatch","SourceAPI","generateConfig","tmpJson","tmpTextarea","tmpLogFlag","tmpMaxFlag","tmpExportMax","tmpCliDiv","tmpOneShotDiv","tmpOneShot","tmpMdwintConfig","tmpMdwintJSON","copyConfig","navigator","clipboard","writeText","copyCLI","tmpCmd","copyOneShot","downloadConfig","tmpBlob","Blob","tmpAnchor","href","createObjectURL","download","click","revokeObjectURL","copyMdwintConfig","copyMdwintCLI","downloadMdwintConfig","toggleSection","pSectionId","tmpCard","toggle","expandAllSections","tmpCards","remove","tmpDetail","tmpToggle","tmpBody","TableCount","renderTableList","loadSavedSelections","saveSelections","tmpSelected","updateSelectionCount","tmpFetchedTables","tmpCount","tmpSavedSet","setAttribute","tmpCheckbox","id","htmlFor","filterTableList","tmpFilter","tmpItems","children","selectAllTables","pChecked","configureSession","authenticate","Authenticated","checkSession","Configured","deauthenticate","tmpPageSize","tmpDateTimePrecisionMS","tmpSyncDeletedRecords","tmpLogToFile","tmpPostBody","SyncMode","MaxRecordsPerEntity","LogToFile","stopSync","pollSyncStatus","stopPolling","renderSyncProgress","Running","Stopping","tmpHasErrors","tmpHasPartial","tmpNames","fetchSyncReport","renderSyncReport","pReport","tmpCardsContainer","tmpOutcomeClass","tmpOutcomeColor","Partial","Stopped","tmpDurationSec","tmpDurationStr","tmpTotalSynced","tmpTotalRecords","Complete","tmpAnomalyContainer","Anomalies","tmpAnomaly","tmpTypeColor","tmpTopContainer","tmpTopCount","tmpDur","tmpRecs","tmpStatusColor","downloadReport","Date","toISOString","slice","copyReport","tmpSyncing","fRenderRow","pName","pTable","tmpStatusBadge","tmpDetails","Skipped","tmpShowCount","tmpSelect","tmpCurrentValue","tmpDeployedTables","tmpOpt","loadTableData","tmpLimit","renderDataTable","pRows","tmpColumns","tmpDisplay"],"mappings":"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","file":"data-cloner.min.js","sourcesContent":["(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.dataCloner = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\nmodule.exports={\n \"name\": \"fable-serviceproviderbase\",\n \"version\": \"3.0.19\",\n \"description\": \"Simple base classes for fable services.\",\n \"main\": \"source/Fable-ServiceProviderBase.js\",\n \"scripts\": {\n \"start\": \"node source/Fable-ServiceProviderBase.js\",\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"types\": \"tsc -p ./tsconfig.build.json\",\n \"check\": \"tsc -p . --noEmit\"\n },\n \"types\": \"types/source/Fable-ServiceProviderBase.d.ts\",\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/stevenvelozo/fable-serviceproviderbase.git\"\n },\n \"keywords\": [\n \"entity\",\n \"behavior\"\n ],\n \"author\": \"Steven Velozo <steven@velozo.com> (http://velozo.com/)\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/fable-serviceproviderbase/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/fable-serviceproviderbase\",\n \"devDependencies\": {\n \"@types/mocha\": \"^10.0.10\",\n \"fable\": \"^3.1.62\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n }\n}\n\n},{}],2:[function(require,module,exports){\n/**\n* Fable Service Base\n* @author <steven@velozo.com>\n*/\n\nconst libPackage = require('../package.json');\n\nclass FableServiceProviderBase\n{\n\t/**\n\t * The constructor can be used in two ways:\n\t * 1) With a fable, options object and service hash (the options object and service hash are optional)a\n\t * 2) With an object or nothing as the first parameter, where it will be treated as the options object\n\t *\n\t * @param {import('fable')|Record<string, any>} [pFable] - (optional) The fable instance, or the options object if there is no fable\n\t * @param {Record<string, any>|string} [pOptions] - (optional) The options object, or the service hash if there is no fable\n\t * @param {string} [pServiceHash] - (optional) The service hash to identify this service instance\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t/** @type {import('fable')} */\n\t\tthis.fable;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.options;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.services;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.servicesMap;\n\n\t\t// Check if a fable was passed in; connect it if so\n\t\tif ((typeof(pFable) === 'object') && pFable.isFable)\n\t\t{\n\t\t\tthis.connectFable(pFable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.fable = false;\n\t\t}\n\n\t\t// Initialize the services map if it wasn't passed in\n\t\t/** @type {Record<string, any>} */\n\t\tthis._PackageFableServiceProvider = libPackage;\n\n\t\t// initialize options and UUID based on whether the fable was passed in or not.\n\t\tif (this.fable)\n\t\t{\n\t\t\tthis.UUID = pFable.getUUID();\n\t\t\tthis.options = (typeof(pOptions) === 'object') ? pOptions\n\t\t\t\t\t\t\t: {};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// With no fable, check to see if there was an object passed into either of the first two\n\t\t\t// Parameters, and if so, treat it as the options object\n\t\t\tthis.options = ((typeof(pFable) === 'object') && !pFable.isFable) ? pFable\n\t\t\t\t\t\t\t: (typeof(pOptions) === 'object') ? pOptions\n\t\t\t\t\t\t\t: {};\n\t\t\tthis.UUID = `CORE-SVC-${Math.floor((Math.random() * (99999 - 10000)) + 10000)}`\n\t\t}\n\n\t\t// It's expected that the deriving class will set this\n\t\tthis.serviceType = `Unknown-${this.UUID}`;\n\n\t\t// The service hash is used to identify the specific instantiation of the service in the services map\n\t\tthis.Hash = (typeof(pServiceHash) === 'string') ? pServiceHash \n\t\t\t\t\t: (!this.fable && (typeof(pOptions) === 'string')) ? pOptions\n\t\t\t\t\t: `${this.UUID}`;\n\t}\n\n\t/**\n\t * @param {import('fable')} pFable\n\t */\n\tconnectFable(pFable)\n\t{\n\t\tif ((typeof(pFable) !== 'object') || (!pFable.isFable))\n\t\t{\n\t\t\tlet tmpErrorMessage = `Fable Service Provider Base: Cannot connect to Fable, invalid Fable object passed in. The pFable parameter was a [${typeof(pFable)}].}`;\n\t\t\tconsole.log(tmpErrorMessage);\n\t\t\treturn new Error(tmpErrorMessage);\n\t\t}\n\n\t\tif (!this.fable)\n\t\t{\n\t\t\tthis.fable = pFable;\n\t\t}\n\n\t\tif (!this.log)\n\t\t{\n\t\t\tthis.log = this.fable.Logging;\n\t\t}\n\t\tif (!this.services)\n\t\t{\n\t\t\tthis.services = this.fable.services;\n\t\t}\n\n\t\tif (!this.servicesMap)\n\t\t{\n\t\t\tthis.servicesMap = this.fable.servicesMap;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tstatic isFableService = true;\n}\n\nmodule.exports = FableServiceProviderBase;\n\n// This is left here in case we want to go back to having different code/base class for \"core\" services\nmodule.exports.CoreServiceProviderBase = FableServiceProviderBase;\n\n},{\"../package.json\":1}],3:[function(require,module,exports){\nmodule.exports={\n \"name\": \"pict-application\",\n \"version\": \"1.0.33\",\n \"description\": \"Application base class for a pict view-based application\",\n \"main\": \"source/Pict-Application.js\",\n \"scripts\": {\n \"test\": \"npx quack test\",\n \"start\": \"node source/Pict-Application.js\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-application-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-application-dev -p 30001:8080 -p 38086:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-application\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-application-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-application-dev /bin/bash\",\n \"tests\": \"npx quack test -g\",\n \"lint\": \"eslint source/**\",\n \"types\": \"tsc -p .\"\n },\n \"types\": \"types/source/Pict-Application.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-application.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-application/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-application#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.28.0\",\n \"browser-env\": \"^3.3.0\",\n \"eslint\": \"^9.28.0\",\n \"pict\": \"^1.0.348\",\n \"pict-provider\": \"^1.0.10\",\n \"pict-view\": \"^1.0.66\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"dependencies\": {\n \"fable-serviceproviderbase\": \"^3.0.19\"\n }\n}\n\n},{}],4:[function(require,module,exports){\nconst libFableServiceBase = require('fable-serviceproviderbase')\n\nconst libPackage = require('../package.json');\n\nconst defaultPictSettings = (\n\t{\n\t\tName: 'DefaultPictApplication',\n\n\t\t// The main \"viewport\" is the view that is used to host our application\n\t\tMainViewportViewIdentifier: 'Default-View',\n\t\tMainViewportRenderableHash: false,\n\t\tMainViewportDestinationAddress: false,\n\t\tMainViewportDefaultDataAddress: false,\n\n\t\t// Whether or not we should automatically render the main viewport and other autorender views after we initialize the pict application\n\t\tAutoSolveAfterInitialize: true,\n\t\tAutoRenderMainViewportViewAfterInitialize: true,\n\t\tAutoRenderViewsAfterInitialize: false,\n\t\tAutoLoginAfterInitialize: false,\n\t\tAutoLoadDataAfterLogin: false,\n\n\t\tConfigurationOnlyViews: [],\n\n\t\tManifests: {},\n\t\t// The prefix to prepend on all template destination hashes\n\t\tIdentifierAddressPrefix: 'PICT-'\n\t});\n\n/**\n * Base class for pict applications.\n */\nclass PictApplication extends libFableServiceBase\n{\n\t/**\n\t * @param {import('fable')} pFable\n\t * @param {Record<string, any>} [pOptions]\n\t * @param {string} [pServiceHash]\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tlet tmpCarryOverConfiguration = (typeof(pFable.settings.PictApplicationConfiguration) === 'object') ? pFable.settings.PictApplicationConfiguration : {};\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictSettings)), tmpCarryOverConfiguration, pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\t/** @type {any} */\n\t\tthis.options;\n\t\t/** @type {any} */\n\t\tthis.log;\n\t\t/** @type {import('pict') & import('fable')} */\n\t\tthis.fable;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {string} */\n\t\tthis.Hash;\n\t\t/**\n\t\t * @type {{ [key: string]: any }}\n\t\t */\n\t\tthis.servicesMap;\n\n\t\tthis.serviceType = 'PictApplication';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\n\t\t// Convenience and consistency naming\n\t\tthis.pict = this.fable;\n\t\t// Wire in the essential Pict state\n\t\t/** @type {Record<string, any>} */\n\t\tthis.AppData = this.fable.AppData;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.Bundle = this.fable.Bundle;\n\n\t\t/** @type {number} */\n\t\tthis.initializeTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastSolvedTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastLoginTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastMarshalFromViewsTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastMarshalToViewsTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastAutoRenderTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastLoadDataTimestamp;\n\n\t\t// Load all the manifests for the application\n\t\tlet tmpManifestKeys = Object.keys(this.options.Manifests);\n\t\tif (tmpManifestKeys.length > 0)\n\t\t{\n\t\t\tfor (let i = 0; i < tmpManifestKeys.length; i++)\n\t\t\t{\n\t\t\t\t// Load each manifest\n\t\t\t\tlet tmpManifestKey = tmpManifestKeys[i];\n\t\t\t\tthis.fable.instantiateServiceProvider('Manifest', this.options.Manifests[tmpManifestKey], tmpManifestKey);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Solve All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonPreSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onPreSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonPreSolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeSolveAsync(fCallback)\n\t{\n\t\tthis.onBeforeSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonSolveAsync(fCallback)\n\t{\n\t\tthis.onSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tsolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing solve() function...`)\n\t\t}\n\n\t\t// Walk through any loaded providers and solve them as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSolve.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpProvidersToSolve.length; i++)\n\t\t{\n\t\t\ttmpProvidersToSolve[i].solve(tmpProvidersToSolve[i]);\n\t\t}\n\n\t\tthis.onBeforeSolve();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t{\n\t\t\t\ttmpViewsToSolve.push(tmpView);\n\t\t\t}\n\t\t}\n\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpViewsToSolve.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\tfor (let i = 0; i < tmpViewsToSolve.length; i++)\n\t\t{\n\t\t\ttmpViewsToSolve[i].solve();\n\t\t}\n\t\tthis.onSolve();\n\t\tthis.onAfterSolve();\n\t\tthis.lastSolvedTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));\n\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\t\t// Walk through any loaded providers and solve them as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSolve.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpProvidersToSolve.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvidersToSolve[i].solveAsync.bind(tmpProvidersToSolve[i]));\n\t\t}\n\n\t\t// Walk through any loaded views and solve them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpViewsToSolve.push(tmpView);\n\t\t\t}\n\t\t}\n\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpViewsToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpViewsToSolve.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToSolve[i].solveAsync.bind(tmpViewsToSolve[i]));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSolvedTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterSolveAsync(fCallback)\n\t{\n\t\tthis.onAfterSolve();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application Login */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tloginAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeLoginAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onLoginAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterLoginAsync.bind(this));\n\n\t\t// check and see if we should automatically trigger a data load\n\t\tif (this.options.AutoLoadDataAfterLogin)\n\t\t{\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tif (!this.isLoggedIn())\n\t\t\t\t{\n\t\t\t\t\treturn fNext();\n\t\t\t\t}\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto loading data after login...`);\n\t\t\t\t}\n\t\t\t\t//TODO: should data load errors funnel here? this creates a weird coupling between login and data load callbacks\n\t\t\t\tthis.loadDataAsync((pError) =>\n\t\t\t\t{\n\t\t\t\t\tfNext(pError);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastLoginTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Check if the application state is logged in. Defaults to true. Override this method in your application based on login requirements.\n\t *\n\t * @return {boolean}\n\t */\n\tisLoggedIn()\n\t{\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application LoadData */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tloadDataAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeLoadDataAsync.bind(this));\n\n\t\t// Walk through any loaded providers and load their data as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToLoadData = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoLoadDataWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToLoadData.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToLoadData.sort((a, b) => { return a.options.AutoLoadDataOrdinal - b.options.AutoLoadDataOrdinal; });\n\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onBeforeLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onLoadDataAsync.bind(this));\n\n\t\t//TODO: think about ways to parallelize these\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onAfterLoadDataAsync.bind(this));\n\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onAfterLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t/** @param {Error} [pError] */\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastLoadDataTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application SaveData */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tsaveDataAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSaveDataAsync.bind(this));\n\n\t\t// Walk through any loaded providers and load their data as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSaveData = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSaveDataWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSaveData.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSaveData.sort((a, b) => { return a.options.AutoSaveDataOrdinal - b.options.AutoSaveDataOrdinal; });\n\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onBeforeSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onSaveDataAsync.bind(this));\n\n\t\t//TODO: think about ways to parallelize these\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onAfterSaveDataAsync.bind(this));\n\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onAfterSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t/** @param {Error} [pError] */\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSaveDataTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialize Application */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\n\t\t\tif ('ConfigurationOnlyViews' in this.options)\n\t\t\t{\n\t\t\t\t// Load all the configuration only views\n\t\t\t\tfor (let i = 0; i < this.options.ConfigurationOnlyViews.length; i++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpViewIdentifier = (typeof(this.options.ConfigurationOnlyViews[i].ViewIdentifier) === 'undefined') ? `AutoView-${this.fable.getUUID()}`\n\t\t\t\t\t\t\t\t\t\t\t: this.options.ConfigurationOnlyViews[i].ViewIdentifier;\n\t\t\t\t\tthis.log.info(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} adding configuration only view: ${tmpViewIdentifier}`);\n\t\t\t\t\tthis.pict.addView(tmpViewIdentifier, this.options.ConfigurationOnlyViews[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.onInitialize();\n\n\t\t\t// Walk through any loaded providers and initialize them as well.\n\t\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\t\tlet tmpProvidersToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\t\tif (tmpProvider.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpProvidersToInitialize.push(tmpProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpProvidersToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpProvidersToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpProvidersToInitialize[i].initialize();\n\t\t\t}\n\n\t\t\t// Now walk through any loaded views and initialize them as well.\n\t\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t\tlet tmpViewsToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpViewsToInitialize.push(tmpView);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpViewsToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpViewsToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpViewsToInitialize[i].initialize();\n\t\t\t}\n\n\t\t\tthis.onAfterInitialize();\n\t\t\tif (this.options.AutoSolveAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto solving after initialization...`);\n\t\t\t\t}\n\t\t\t\t// Solve the template synchronously\n\t\t\t\tthis.solve();\n\t\t\t}\n\t\t\t// Now check and see if we should automatically render as well\n\t\t\tif (this.options.AutoRenderMainViewportViewAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto rendering after initialization...`);\n\t\t\t\t}\n\t\t\t\t// Render the template synchronously\n\t\t\t\tthis.render();\n\t\t\t}\n\t\t\tthis.initializeTimestamp = this.fable.log.getTimeStamp();\n\t\t\tthis.onCompletionOfInitialize();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync:`);\n\t\t}\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 3)\n\t\t\t{\n\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning initialization...`);\n\t\t\t}\n\n\t\t\tif ('ConfigurationOnlyViews' in this.options)\n\t\t\t{\n\t\t\t\t// Load all the configuration only views\n\t\t\t\tfor (let i = 0; i < this.options.ConfigurationOnlyViews.length; i++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpViewIdentifier = (typeof(this.options.ConfigurationOnlyViews[i].ViewIdentifier) === 'undefined') ? `AutoView-${this.fable.getUUID()}`\n\t\t\t\t\t\t\t\t\t\t\t: this.options.ConfigurationOnlyViews[i].ViewIdentifier;\n\t\t\t\t\tthis.log.info(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} adding configuration only view: ${tmpViewIdentifier}`);\n\t\t\t\t\tthis.pict.addView(tmpViewIdentifier, this.options.ConfigurationOnlyViews[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\n\t\t\t// Walk through any loaded providers and solve them as well.\n\t\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\t\tlet tmpProvidersToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\t\tif (tmpProvider.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpProvidersToInitialize.push(tmpProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpProvidersToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpProvidersToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpAnticipate.anticipate(tmpProvidersToInitialize[i].initializeAsync.bind(tmpProvidersToInitialize[i]));\n\t\t\t}\n\n\t\t\t// Now walk through any loaded views and initialize them as well.\n\t\t\t// TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.\n\t\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t\tlet tmpViewsToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpViewsToInitialize.push(tmpView);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the views by their priority\n\t\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\t\ttmpViewsToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpViewsToInitialize.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = tmpViewsToInitialize[i];\n\t\t\t\ttmpAnticipate.anticipate(tmpView.initializeAsync.bind(tmpView));\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\tif (this.options.AutoLoginAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto login (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.loginAsync.bind(this));\n\t\t\t}\n\n\t\t\tif (this.options.AutoSolveAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto solving (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.solveAsync.bind(this));\n\t\t\t}\n\n\t\t\tif (this.options.AutoRenderMainViewportViewAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto rendering (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.renderMainViewportAsync.bind(this));\n\t\t\t}\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync Error: ${pError.message || pError}`, { stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\tthis.initializeTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn tmpCallback();\n\t\t\t\t});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn this.onCompletionOfInitializeAsync(tmpCallback);\n\t\t}\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonCompletionOfInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onCompletionOfInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonCompletionOfInitializeAsync(fCallback)\n\t{\n\t\tthis.onCompletionOfInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal Data From All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tmarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing marshalFromViews() function...`)\n\t\t}\n\t\tthis.onBeforeMarshalFromViews();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalFromViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalFromViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalFromViews.length; i++)\n\t\t{\n\t\t\ttmpViewsToMarshalFromViews[i].marshalFromView();\n\t\t}\n\t\tthis.onMarshalFromViews();\n\t\tthis.onAfterMarshalFromViews();\n\t\tthis.lastMarshalFromViewsTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tmarshalFromViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalFromViewsAsync.bind(this));\n\t\t// Walk through any loaded views and marshalFromViews them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalFromViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalFromViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalFromViews.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToMarshalFromViews[i].marshalFromViewAsync.bind(tmpViewsToMarshalFromViews[i]));\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onMarshalFromViewsAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalFromViewsAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalFromViewsTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal Data To All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tmarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing marshalToViews() function...`)\n\t\t}\n\t\tthis.onBeforeMarshalToViews();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalToViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalToViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalToViews.length; i++)\n\t\t{\n\t\t\ttmpViewsToMarshalToViews[i].marshalToView();\n\t\t}\n\t\tthis.onMarshalToViews();\n\t\tthis.onAfterMarshalToViews();\n\t\tthis.lastMarshalToViewsTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tmarshalToViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalToViewsAsync.bind(this));\n\t\t// Walk through any loaded views and marshalToViews them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalToViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalToViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalToViews.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToMarshalToViews[i].marshalToViewAsync.bind(tmpViewsToMarshalToViews[i]));\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onMarshalToViewsAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalToViewsAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalToViewsTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Render View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeRenderAsync(fCallback)\n\t{\n\t\tthis.onBeforeRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {string} [pViewIdentifier] - The hash of the view to render. By default, the main viewport view is rendered.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string} [pTemplateDataAddress] - The address where the data for the template is stored.\n\t *\n\t * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?\n\t */\n\trender(pViewIdentifier, pRenderableHash, pRenderDestinationAddress, pTemplateDataAddress)\n\t{\n\t\tlet tmpViewIdentifier = (typeof(pViewIdentifier) !== 'string') ? this.options.MainViewportViewIdentifier : pViewIdentifier;\n\t\tlet tmpRenderableHash = (typeof(pRenderableHash) !== 'string') ? this.options.MainViewportRenderableHash : pRenderableHash;\n\t\tlet tmpRenderDestinationAddress = (typeof(pRenderDestinationAddress) !== 'string') ? this.options.MainViewportDestinationAddress : pRenderDestinationAddress;\n\t\tlet tmpTemplateDataAddress = (typeof(pTemplateDataAddress) !== 'string') ? this.options.MainViewportDefaultDataAddress : pTemplateDataAddress;\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} VIEW Renderable[${tmpRenderableHash}] Destination[${tmpRenderDestinationAddress}] TemplateDataAddress[${tmpTemplateDataAddress}] render:`);\n\t\t}\n\n\t\tthis.onBeforeRender();\n\n\t\t// Now get the view (by hash) from the loaded views\n\t\tlet tmpView = (typeof (tmpViewIdentifier) === 'string') ? this.servicesMap.PictView[tmpViewIdentifier] : false;\n\t\tif (!tmpView)\n\t\t{\n\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} could not render from View ${tmpViewIdentifier} because it is not a valid view.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.onRender();\n\n\t\ttmpView.render(tmpRenderableHash, tmpRenderDestinationAddress, tmpTemplateDataAddress);\n\n\t\tthis.onAfterRender();\n\n\t\treturn true;\n\t}\n\t/**\n\t * @return {boolean}\n\t */\n\tonRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonRenderAsync(fCallback)\n\t{\n\t\tthis.onRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {string|((error?: Error) => void)} pViewIdentifier - The hash of the view to render. By default, the main viewport view is rendered. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pRenderableHash] - The hash of the renderable to render. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pRenderDestinationAddress] - The address where the renderable will be rendered. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pTemplateDataAddress] - The address where the data for the template is stored. (or the callback)\n\t * @param {(error?: Error) => void} [fCallback] - The callback, if all other parameters are provided.\n\t *\n\t * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?\n\t */\n\trenderAsync(pViewIdentifier, pRenderableHash, pRenderDestinationAddress, pTemplateDataAddress, fCallback)\n\t{\n\t\tlet tmpViewIdentifier = (typeof(pViewIdentifier) !== 'string') ? this.options.MainViewportViewIdentifier : pViewIdentifier;\n\t\tlet tmpRenderableHash = (typeof(pRenderableHash) !== 'string') ? this.options.MainViewportRenderableHash : pRenderableHash;\n\t\tlet tmpRenderDestinationAddress = (typeof(pRenderDestinationAddress) !== 'string') ? this.options.MainViewportDestinationAddress : pRenderDestinationAddress;\n\t\tlet tmpTemplateDataAddress = (typeof(pTemplateDataAddress) !== 'string') ? this.options.MainViewportDefaultDataAddress : pTemplateDataAddress;\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateDataAddress) === 'function') ? pTemplateDataAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\t(typeof(pViewIdentifier) === 'function') ? pViewIdentifier :\n\t\t\t\t\t\t\tfalse;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} VIEW Renderable[${tmpRenderableHash}] Destination[${tmpRenderDestinationAddress}] TemplateDataAddress[${tmpTemplateDataAddress}] renderAsync:`);\n\t\t}\n\n\t\tlet tmpRenderAnticipate = this.fable.newAnticipate();\n\n\t\ttmpRenderAnticipate.anticipate(this.onBeforeRenderAsync.bind(this));\n\n\t\tlet tmpView = (typeof (tmpViewIdentifier) === 'string') ? this.servicesMap.PictView[tmpViewIdentifier] : false;\n\t\tif (!tmpView)\n\t\t{\n\t\t\tlet tmpErrorMessage = `PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} could not asynchronously render from View ${tmpViewIdentifier} because it is not a valid view.`;\n\t\t\tif (this.pict.LogNoisiness > 3)\n\t\t\t{\n\t\t\t\tthis.log.error(tmpErrorMessage);\n\t\t\t}\n\t\t\treturn tmpCallback(new Error(tmpErrorMessage));\n\t\t}\n\n\t\ttmpRenderAnticipate.anticipate(this.onRenderAsync.bind(this));\n\n\t\ttmpRenderAnticipate.anticipate(\n\t\t\t(fNext) =>\n\t\t\t{\n\t\t\t\ttmpView.renderAsync.call(tmpView, tmpRenderableHash, tmpRenderDestinationAddress, tmpTemplateDataAddress, fNext);\n\t\t\t});\n\n\t\ttmpRenderAnticipate.anticipate(this.onAfterRenderAsync.bind(this));\n\n\t\treturn tmpRenderAnticipate.wait(tmpCallback);\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterRenderAsync(fCallback)\n\t{\n\t\tthis.onAfterRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\trenderMainViewport()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderMainViewport:`);\n\t\t}\n\n\t\treturn this.render();\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\trenderMainViewportAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderMainViewportAsync:`);\n\t\t}\n\n\t\treturn this.renderAsync(fCallback);\n\t}\n\t/**\n\t * @return {void}\n\t */\n\trenderAutoViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning renderAutoViews...`);\n\t\t}\n\t\t// Now walk through any loaded views and sort them by the AutoRender ordinal\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t// Sort the views by their priority\n\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\ttmpLoadedViews.sort((a, b) =>\n\t\t{\n\t\t\treturn this.pict.views[a].options.AutoRenderOrdinal - this.pict.views[b].options.AutoRenderOrdinal;\n\t\t});\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoRender)\n\t\t\t{\n\t\t\t\ttmpView.render();\n\t\t\t}\n\t\t}\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync complete.`);\n\t\t}\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\trenderAutoViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\tfalse;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning renderAutoViewsAsync...`);\n\t\t}\n\n\t\t// Now walk through any loaded views and sort them by the AutoRender ordinal\n\t\t// TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t// Sort the views by their priority\n\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\ttmpLoadedViews.sort((a, b) =>\n\t\t{\n\t\t\treturn this.pict.views[a].options.AutoRenderOrdinal - this.pict.views[b].options.AutoRenderOrdinal;\n\t\t});\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoRender)\n\t\t\t{\n\t\t\t\ttmpAnticipate.anticipate(tmpView.renderAsync.bind(tmpView));\n\t\t\t}\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tthis.lastAutoRenderTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync complete.`);\n\t\t\t\t}\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tget isPictApplication()\n\t{\n\t\treturn true;\n\t}\n}\n\nmodule.exports = PictApplication;\n\n},{\"../package.json\":3,\"fable-serviceproviderbase\":2}],5:[function(require,module,exports){\nmodule.exports={\n \"name\": \"pict-provider\",\n \"version\": \"1.0.12\",\n \"description\": \"Pict Provider Base Class\",\n \"main\": \"source/Pict-Provider.js\",\n \"scripts\": {\n \"start\": \"node source/Pict-Provider.js\",\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-provider-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-provider-dev -p 24125:8080 -p 30027:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-provider\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-provider-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-provider-dev /bin/bash\",\n \"lint\": \"eslint source/**\",\n \"types\": \"tsc -p .\"\n },\n \"types\": \"types/source/Pict-Provider.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-provider.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-provider/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-provider#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.1\",\n \"eslint\": \"^9.39.1\",\n \"pict\": \"^1.0.351\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"dependencies\": {\n \"fable-serviceproviderbase\": \"^3.0.19\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n }\n}\n\n},{}],6:[function(require,module,exports){\nconst libFableServiceBase = require('fable-serviceproviderbase');\n\nconst libPackage = require('../package.json');\n\nconst defaultPictProviderSettings = (\n\t{\n\t\tProviderIdentifier: false,\n\n\t\t// If this is set to true, when the App initializes this will.\n\t\t// After the App initializes, initialize will be called as soon as it's added.\n\t\tAutoInitialize: true,\n\t\tAutoInitializeOrdinal: 0,\n\n\t\tAutoLoadDataWithApp: true,\n\t\tAutoLoadDataOrdinal: 0,\n\n\t\tAutoSolveWithApp: true,\n\t\tAutoSolveOrdinal: 0,\n\n\t\tManifests: {},\n\n\t\tTemplates: []\n\t});\n\nclass PictProvider extends libFableServiceBase\n{\n\t/**\n\t * @param {import('fable')} pFable - The Fable instance.\n\t * @param {Record<string, any>} [pOptions] - The options for the provider.\n\t * @param {string} [pServiceHash] - The service hash for the provider.\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t// Intersect default options, parent constructor, service information\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictProviderSettings)), pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\t/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */\n\t\tthis.fable;\n\t\t/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */\n\t\tthis.pict;\n\t\t/** @type {any} */\n\t\tthis.log;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.options;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {string} */\n\t\tthis.Hash;\n\n\t\tif (!this.options.ProviderIdentifier)\n\t\t{\n\t\t\tthis.options.ProviderIdentifier = `AutoProviderID-${this.fable.getUUID()}`;\n\t\t}\n\n\t\tthis.serviceType = 'PictProvider';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\n\t\t// Convenience and consistency naming\n\t\tthis.pict = this.fable;\n\n\t\t// Wire in the essential Pict application state\n\t\t/** @type {Record<string, any>} */\n\t\tthis.AppData = this.pict.AppData;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.Bundle = this.pict.Bundle;\n\n\t\tthis.initializeTimestamp = false;\n\t\tthis.lastSolvedTimestamp = false;\n\n\t\tfor (let i = 0; i < this.options.Templates.length; i++)\n\t\t{\n\t\t\tlet tmpDefaultTemplate = this.options.Templates[i];\n\n\t\t\tif (!tmpDefaultTemplate.hasOwnProperty('Postfix') || !tmpDefaultTemplate.hasOwnProperty('Template'))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} could not load Default Template ${i} in the options array.`, tmpDefaultTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpDefaultTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpDefaultTemplate.Source = `PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix, tmpDefaultTemplate.Postfix, tmpDefaultTemplate.Template, tmpDefaultTemplate.Source);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialization */\n\t/* -------------------------------------------------------------------------- */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-pinitialization.\n\t *\n\t * @return {void}\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\tonInitialize()\n\t{\n\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow PROVIDER [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\t\t\tthis.onInitialize();\n\t\t\tthis.onAfterInitialize();\n\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow PROVIDER [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initializeAsync:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.info(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} beginning initialization...`);\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialization failed: ${pError.message || pError}`, { Stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\telse if (this.pict.LogNoisiness > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.info(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fCallback();\n\t\t\t\t})\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn fCallback();\n\t\t}\n\t}\n\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\tonPreRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onPreRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-render.\n\t *\n\t * @return {void}\n\t */\n\tonPreRenderAsync(fCallback)\n\t{\n\t\tthis.onPreRender();\n\t\treturn fCallback();\n\t}\n\n\trender()\n\t{\n\t\treturn this.onPreRender();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after render.\n\t *\n\t * @return {void}\n\t */\n\trenderAsync(fCallback)\n\t{\n\t\tthis.onPreRender();\n\t\treturn fCallback();\n\t}\n\n\tonPreSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onPreSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-solve.\n\t *\n\t * @return {void}\n\t */\n\tonPreSolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\tsolve()\n\t{\n\t\treturn this.onPreSolve();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after solve.\n\t *\n\t * @return {void}\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.\n\t */\n\tonBeforeLoadDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Hook to allow the provider to load data during application data load.\n\t *\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.\n\t */\n\tonLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.\n\t */\n\tonAfterLoadDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.\n\t *\n\t * @return {void}\n\t */\n\tonBeforeSaveDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Hook to allow the provider to load data during application data load.\n\t *\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.\n\t *\n\t * @return {void}\n\t */\n\tonSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.\n\t *\n\t * @return {void}\n\t */\n\tonAfterSaveDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n}\n\nmodule.exports = PictProvider;\n\n},{\"../package.json\":5,\"fable-serviceproviderbase\":2}],7:[function(require,module,exports){\nmodule.exports = (\n{\n\t\"RenderOnLoad\": true,\n\n\t\"DefaultRenderable\": \"Histogram-Wrap\",\n\t\"DefaultDestinationAddress\": \"#Histogram-Container-Div\",\n\n\t\"Templates\":\n\t[\n\t\t{\n\t\t\t\"Hash\": \"Histogram-Container\",\n\t\t\t\"Template\": \"<!-- Histogram Container Rendering Soon -->\"\n\t\t}\n\t],\n\n\t\"Renderables\":\n\t[\n\t\t{\n\t\t\t\"RenderableHash\": \"Histogram-Wrap\",\n\t\t\t\"TemplateHash\": \"Histogram-Container\",\n\t\t\t\"DestinationAddress\": \"#Histogram-Container-Div\"\n\t\t}\n\t],\n\n\t\"TargetElementAddress\": \"#Histogram-Container-Div\",\n\n\t// --- Data Configuration ---\n\n\t// Address in AppData (or other Pict address space) for the histogram bins\n\t// Expected format: Array of objects with at least { Label, Value } properties\n\t// e.g. [{ Label: \"2020\", Value: 15 }, { Label: \"2021\", Value: 42 }]\n\t\"DataAddress\": false,\n\n\t// Alternatively, provide bins directly (used if DataAddress is not set)\n\t\"Bins\": [],\n\n\t// Property names within each bin object\n\t\"LabelProperty\": \"Label\",\n\t\"ValueProperty\": \"Value\",\n\n\t// --- Layout Configuration ---\n\n\t// \"vertical\" = bars grow upward; \"horizontal\" = bars grow rightward\n\t\"Orientation\": \"vertical\",\n\n\t// The rendering mode: \"browser\", \"consoleui\", or \"cli\"\n\t// \"browser\" renders HTML/CSS/SVG; \"consoleui\" renders via blessed widgets;\n\t// \"cli\" renders ANSI text to stdout\n\t\"RenderMode\": \"browser\",\n\n\t// Maximum height in pixels (browser vertical) or characters (cli/consoleui)\n\t\"MaxBarSize\": 200,\n\n\t// Bar thickness in pixels (browser) or characters (cli/consoleui)\n\t\"BarThickness\": 30,\n\n\t// Gap between bars in pixels (browser) or characters (cli/consoleui)\n\t\"BarGap\": 4,\n\n\t// Whether to show value labels on/above bars\n\t\"ShowValues\": true,\n\n\t// Whether to show bin labels (x-axis for vertical, y-axis for horizontal)\n\t\"ShowLabels\": true,\n\n\t// Color of the bars (CSS color for browser, ANSI color name for cli/consoleui)\n\t\"BarColor\": \"#4A90D9\",\n\n\t// Color of selected bars\n\t\"SelectedBarColor\": \"#2ECC71\",\n\n\t// Color of bars in the selection range\n\t\"SelectionRangeColor\": \"#85C1E9\",\n\n\t// --- Selection Configuration ---\n\n\t// Enable selection mode\n\t\"Selectable\": false,\n\n\t// Selection mode: \"single\", \"multiple\", \"range\"\n\t// \"single\" - click to select one bar\n\t// \"multiple\" - click to toggle individual bars\n\t// \"range\" - drag sliders to select a contiguous range of bins\n\t\"SelectionMode\": \"range\",\n\n\t// Address in AppData to write selection state\n\t// Will contain { SelectedIndices: [], RangeStart: N, RangeEnd: N } or similar\n\t\"SelectionDataAddress\": false,\n\n\t// Initial selection (array of indices or { Start, End } for range mode)\n\t\"InitialSelection\": null,\n\n\t// --- CLI/ConsoleUI Configuration ---\n\n\t// Characters used for rendering in text mode\n\t\"BarCharacter\": \"\\u2588\",\n\t\"BarPartialCharacters\": [\" \", \"\\u2581\", \"\\u2582\", \"\\u2583\", \"\\u2584\", \"\\u2585\", \"\\u2586\", \"\\u2587\", \"\\u2588\"],\n\t\"EmptyCharacter\": \" \",\n\t\"SliderCharacter\": \"\\u2502\",\n\t\"SliderHandleCharacter\": \"\\u25C6\",\n\n\t// Width of the histogram in characters (cli/consoleui)\n\t\"TextWidth\": 60,\n\n\t// Height of the histogram in characters (cli/consoleui vertical)\n\t\"TextHeight\": 15,\n\n\t// --- CSS ---\n\t\"CSS\": `.pict-histogram-container\n{\n\tdisplay: inline-block;\n\tposition: relative;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n\tfont-size: 12px;\n\tuser-select: none;\n}\n.pict-histogram-chart\n{\n\tdisplay: flex;\n\talign-items: flex-end;\n\tposition: relative;\n}\n.pict-histogram-container.pict-histogram-horizontal\n{\n\tdisplay: inline-flex;\n\tflex-direction: row;\n\talign-items: stretch;\n}\n.pict-histogram-chart.pict-histogram-horizontal\n{\n\tflex-direction: column;\n\talign-items: flex-start;\n}\n.pict-histogram-bar-group\n{\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tcursor: default;\n\tflex-shrink: 0;\n}\n.pict-histogram-horizontal .pict-histogram-bar-group\n{\n\tflex-direction: row;\n\talign-items: center;\n}\n.pict-histogram-bar\n{\n\ttransition: background-color 0.15s ease, height 0.2s ease, width 0.2s ease;\n\tborder-radius: 2px 2px 0 0;\n\tmin-width: 1px;\n\tmin-height: 1px;\n}\n.pict-histogram-horizontal .pict-histogram-bar\n{\n\tborder-radius: 0 2px 2px 0;\n}\n.pict-histogram-bar.pict-histogram-selectable\n{\n\tcursor: pointer;\n}\n.pict-histogram-bar.pict-histogram-selectable:hover\n{\n\topacity: 0.8;\n}\n.pict-histogram-bar.pict-histogram-selected\n{\n\tbox-shadow: 0 0 0 2px rgba(46, 204, 113, 0.4);\n}\n.pict-histogram-bar.pict-histogram-in-range\n{\n\topacity: 0.9;\n}\n.pict-histogram-value-label\n{\n\ttext-align: center;\n\tcolor: #666;\n\tfont-size: 11px;\n\tpadding: 2px 0;\n\twhite-space: nowrap;\n}\n.pict-histogram-horizontal .pict-histogram-value-label\n{\n\tpadding: 0 4px;\n}\n.pict-histogram-bin-label\n{\n\ttext-align: center;\n\tcolor: #333;\n\tfont-size: 11px;\n\tpadding: 4px 2px 0 2px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n.pict-histogram-horizontal .pict-histogram-bin-label\n{\n\tpadding: 0 4px 0 0;\n\ttext-align: right;\n\tmin-width: 40px;\n}\n.pict-histogram-range-slider-container\n{\n\tposition: relative;\n\twidth: 100%;\n\theight: 24px;\n\tmargin-top: 4px;\n}\n.pict-histogram-horizontal .pict-histogram-range-slider-container\n{\n\twidth: 24px;\n\theight: auto;\n\talign-self: stretch;\n\tmargin-top: 0;\n\tmargin-left: 4px;\n}\n.pict-histogram-range-track\n{\n\tposition: absolute;\n\ttop: 10px;\n\tleft: 0;\n\tright: 0;\n\theight: 4px;\n\tbackground: #E0E0E0;\n\tborder-radius: 2px;\n}\n.pict-histogram-horizontal .pict-histogram-range-track\n{\n\ttop: 0;\n\tleft: 10px;\n\tright: auto;\n\tbottom: 0;\n\twidth: 4px;\n\theight: auto;\n}\n.pict-histogram-range-fill\n{\n\tposition: absolute;\n\ttop: 10px;\n\theight: 4px;\n\tbackground: #4A90D9;\n\tborder-radius: 2px;\n}\n.pict-histogram-horizontal .pict-histogram-range-fill\n{\n\ttop: auto;\n\tleft: 10px;\n\twidth: 4px;\n\theight: auto;\n}\n.pict-histogram-range-handle\n{\n\tposition: absolute;\n\ttop: 4px;\n\twidth: 16px;\n\theight: 16px;\n\tbackground: #fff;\n\tborder: 2px solid #4A90D9;\n\tborder-radius: 50%;\n\tcursor: grab;\n\tz-index: 2;\n\ttransform: translateX(-50%);\n}\n.pict-histogram-horizontal .pict-histogram-range-handle\n{\n\ttop: auto;\n\tleft: 4px;\n\ttransform: translateY(-50%);\n}\n.pict-histogram-range-handle:active\n{\n\tcursor: grabbing;\n\tbackground: #4A90D9;\n}\n.pict-histogram-range-handle:active,\n.pict-histogram-range-handle:focus\n{\n\tbox-shadow: 0 0 0 3px rgba(74, 144, 217, 0.3);\n\toutline: none;\n}\n`\n});\n\n},{}],8:[function(require,module,exports){\n/**\n * Pict Section Histogram\n *\n * A histogram visualization section for the Pict MVC framework.\n *\n * Supports:\n * - Vertical and horizontal orientation\n * - Three render modes: browser (HTML/CSS), consoleui (blessed), cli (ANSI)\n * - Interactive selection: single click, multi-select, or range slider\n * - Data binding via Pict AppData addresses\n *\n * @module pict-section-histogram\n */\n\nconst libPictViewClass = require('pict-view');\nconst _DefaultConfiguration = require('./Pict-Section-Histogram-DefaultConfiguration.js');\n\nconst libRendererBrowser = require('./renderers/Pict-Histogram-Renderer-Browser.js');\nconst libRendererConsoleUI = require('./renderers/Pict-Histogram-Renderer-ConsoleUI.js');\nconst libRendererCLI = require('./renderers/Pict-Histogram-Renderer-CLI.js');\n\nclass PictSectionHistogram extends libPictViewClass\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tlet tmpOptions = Object.assign({}, _DefaultConfiguration, pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\tthis.initialRenderComplete = false;\n\n\t\t// --- Selection State ---\n\n\t\t// Set of selected bin indices (for \"single\" and \"multiple\" modes)\n\t\tthis._selectedIndices = new Set();\n\n\t\t// Range bounds (for \"range\" mode)\n\t\tthis._selectionRangeStart = 0;\n\t\tthis._selectionRangeEnd = 0;\n\n\t\t// Resolve the renderer for the configured mode\n\t\tthis._renderer = this._resolveRenderer();\n\n\t\t// Apply initial selection if provided\n\t\tthis._applyInitialSelection();\n\t}\n\n\t/**\n\t * Set up the initial selection state from options.\n\t */\n\t_applyInitialSelection()\n\t{\n\t\tif (this.options.InitialSelection)\n\t\t{\n\t\t\tthis.setSelection(this.options.InitialSelection);\n\t\t}\n\t\telse if (this.options.Selectable && this.options.SelectionMode === 'range')\n\t\t{\n\t\t\t// Default: select all bins\n\t\t\tlet tmpBins = this.getBins();\n\t\t\tthis._selectionRangeStart = 0;\n\t\t\tthis._selectionRangeEnd = Math.max(0, tmpBins.length - 1);\n\t\t\tthis._syncSelectionFromRange();\n\t\t}\n\t}\n\n\t/**\n\t * Pick the renderer module based on RenderMode option.\n\t *\n\t * @returns {object} The renderer module { render, wireEvents }\n\t */\n\t_resolveRenderer()\n\t{\n\t\tswitch (this.options.RenderMode)\n\t\t{\n\t\t\tcase 'consoleui':\n\t\t\t\treturn libRendererConsoleUI;\n\t\t\tcase 'cli':\n\t\t\t\treturn libRendererCLI;\n\t\t\tcase 'browser':\n\t\t\tdefault:\n\t\t\t\treturn libRendererBrowser;\n\t\t}\n\t}\n\n\t// --- Data Access ---\n\n\t/**\n\t * Get the current bin data array.\n\t *\n\t * Reads from the configured DataAddress in AppData, falling back to\n\t * the static Bins option.\n\t *\n\t * @returns {Array} Array of bin objects\n\t */\n\tgetBins()\n\t{\n\t\tif (this.options.DataAddress)\n\t\t{\n\t\t\tconst tmpAddressSpace =\n\t\t\t{\n\t\t\t\tFable: this.fable,\n\t\t\t\tPict: this.fable,\n\t\t\t\tAppData: this.AppData,\n\t\t\t\tBundle: this.Bundle,\n\t\t\t\tOptions: this.options\n\t\t\t};\n\t\t\tlet tmpData = this.fable.manifest.getValueByHash(tmpAddressSpace, this.options.DataAddress);\n\t\t\tif (Array.isArray(tmpData))\n\t\t\t{\n\t\t\t\treturn tmpData;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis.log.warn(`PICT-Histogram DataAddress [${this.options.DataAddress}] did not return an array.`);\n\t\t\t}\n\t\t}\n\n\t\treturn this.options.Bins || [];\n\t}\n\n\t/**\n\t * Set the bins programmatically (updates the Bins option).\n\t *\n\t * @param {Array} pBins - Array of bin objects { Label, Value, ... }\n\t */\n\tsetBins(pBins)\n\t{\n\t\tif (!Array.isArray(pBins))\n\t\t{\n\t\t\tthis.log.warn('PICT-Histogram setBins requires an array.');\n\t\t\treturn;\n\t\t}\n\t\tthis.options.Bins = pBins;\n\n\t\t// If we also have a DataAddress, write through\n\t\tif (this.options.DataAddress)\n\t\t{\n\t\t\tconst tmpAddressSpace =\n\t\t\t{\n\t\t\t\tFable: this.fable,\n\t\t\t\tPict: this.fable,\n\t\t\t\tAppData: this.AppData,\n\t\t\t\tBundle: this.Bundle,\n\t\t\t\tOptions: this.options\n\t\t\t};\n\t\t\tthis.fable.manifest.setValueByHash(tmpAddressSpace, this.options.DataAddress, pBins);\n\t\t}\n\t}\n\n\t// --- Selection Logic ---\n\n\t/**\n\t * Check whether a bin index is currently selected.\n\t *\n\t * @param {number} pIndex\n\t * @returns {boolean}\n\t */\n\tisIndexSelected(pIndex)\n\t{\n\t\tif (!this.options.Selectable)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\treturn (pIndex === this._selectionRangeStart || pIndex === this._selectionRangeEnd);\n\t\t}\n\n\t\treturn this._selectedIndices.has(pIndex);\n\t}\n\n\t/**\n\t * Check whether a bin index falls within the current range selection\n\t * (but is not one of the range endpoints).\n\t *\n\t * @param {number} pIndex\n\t * @returns {boolean}\n\t */\n\tisIndexInRange(pIndex)\n\t{\n\t\tif (!this.options.Selectable || this.options.SelectionMode !== 'range')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn (pIndex > this._selectionRangeStart && pIndex < this._selectionRangeEnd);\n\t}\n\n\t/**\n\t * Get the current selection state.\n\t *\n\t * @returns {object} Selection descriptor\n\t */\n\tgetSelection()\n\t{\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\tlet tmpBins = this.getBins();\n\t\t\tlet tmpIndices = [];\n\t\t\tfor (let i = this._selectionRangeStart; i <= this._selectionRangeEnd; i++)\n\t\t\t{\n\t\t\t\ttmpIndices.push(i);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tMode: 'range',\n\t\t\t\tRangeStart: this._selectionRangeStart,\n\t\t\t\tRangeEnd: this._selectionRangeEnd,\n\t\t\t\tSelectedIndices: tmpIndices,\n\t\t\t\tStartLabel: (tmpBins[this._selectionRangeStart] || {})[this.options.LabelProperty],\n\t\t\t\tEndLabel: (tmpBins[this._selectionRangeEnd] || {})[this.options.LabelProperty]\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn {\n\t\t\t\tMode: this.options.SelectionMode,\n\t\t\t\tSelectedIndices: Array.from(this._selectedIndices).sort((a, b) => a - b)\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Programmatically set the selection.\n\t *\n\t * @param {object|Array} pSelection - For range: { Start, End }; for single/multiple: array of indices\n\t */\n\tsetSelection(pSelection)\n\t{\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\tif (pSelection && typeof (pSelection.Start) === 'number' && typeof (pSelection.End) === 'number')\n\t\t\t{\n\t\t\t\tthis._selectionRangeStart = pSelection.Start;\n\t\t\t\tthis._selectionRangeEnd = pSelection.End;\n\t\t\t\tthis._syncSelectionFromRange();\n\t\t\t}\n\t\t}\n\t\telse if (Array.isArray(pSelection))\n\t\t{\n\t\t\tthis._selectedIndices = new Set(pSelection);\n\t\t}\n\n\t\tthis._writeSelectionToAddress();\n\t}\n\n\t/**\n\t * Handle a bar click in single or multiple selection mode.\n\t *\n\t * @param {number} pIndex - The clicked bin index\n\t */\n\thandleBarClick(pIndex)\n\t{\n\t\tif (this.options.SelectionMode === 'single')\n\t\t{\n\t\t\tthis._selectedIndices.clear();\n\t\t\tthis._selectedIndices.add(pIndex);\n\t\t}\n\t\telse if (this.options.SelectionMode === 'multiple')\n\t\t{\n\t\t\tif (this._selectedIndices.has(pIndex))\n\t\t\t{\n\t\t\t\tthis._selectedIndices.delete(pIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis._selectedIndices.add(pIndex);\n\t\t\t}\n\t\t}\n\n\t\tthis._writeSelectionToAddress();\n\t\tthis.onSelectionChange(this.getSelection());\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Handle a bar click in range mode — moves the nearest handle.\n\t *\n\t * @param {number} pIndex - The clicked bin index\n\t */\n\thandleRangeBarClick(pIndex)\n\t{\n\t\tlet tmpDistStart = Math.abs(pIndex - this._selectionRangeStart);\n\t\tlet tmpDistEnd = Math.abs(pIndex - this._selectionRangeEnd);\n\n\t\tif (tmpDistStart <= tmpDistEnd)\n\t\t{\n\t\t\tthis._selectionRangeStart = Math.min(pIndex, this._selectionRangeEnd);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis._selectionRangeEnd = Math.max(pIndex, this._selectionRangeStart);\n\t\t}\n\n\t\tthis._syncSelectionFromRange();\n\t\tthis._writeSelectionToAddress();\n\t\tthis.onSelectionChange(this.getSelection());\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Sync _selectedIndices from the range bounds (so getSelection is consistent).\n\t */\n\t_syncSelectionFromRange()\n\t{\n\t\tthis._selectedIndices.clear();\n\t\tfor (let i = this._selectionRangeStart; i <= this._selectionRangeEnd; i++)\n\t\t{\n\t\t\tthis._selectedIndices.add(i);\n\t\t}\n\t}\n\n\t/**\n\t * Write the current selection state to the configured SelectionDataAddress.\n\t */\n\t_writeSelectionToAddress()\n\t{\n\t\tif (!this.options.SelectionDataAddress)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tconst tmpAddressSpace =\n\t\t{\n\t\t\tFable: this.fable,\n\t\t\tPict: this.fable,\n\t\t\tAppData: this.AppData,\n\t\t\tBundle: this.Bundle,\n\t\t\tOptions: this.options\n\t\t};\n\n\t\tthis.fable.manifest.setValueByHash(tmpAddressSpace, this.options.SelectionDataAddress, this.getSelection());\n\t}\n\n\t/**\n\t * Hook for subclasses or consumers to react to selection changes.\n\t *\n\t * @param {object} pSelection - The new selection state\n\t */\n\tonSelectionChange(pSelection)\n\t{\n\t\t// Override in subclass or assign externally\n\t}\n\n\t// --- Lifecycle Hooks ---\n\n\tonBeforeInitialize()\n\t{\n\t\tsuper.onBeforeInitialize();\n\t\treturn super.onBeforeInitialize();\n\t}\n\n\tonAfterRender(pRenderable)\n\t{\n\t\t// Inject CSS\n\t\tthis.pict.CSSMap.injectCSS();\n\n\t\tif (!this.initialRenderComplete)\n\t\t{\n\t\t\tthis.onAfterInitialRender();\n\t\t\tthis.initialRenderComplete = true;\n\t\t}\n\n\t\treturn super.onAfterRender(pRenderable);\n\t}\n\n\tonAfterInitialRender()\n\t{\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Render the histogram using the active renderer and wire events.\n\t */\n\trenderHistogram()\n\t{\n\t\t// Ensure CSS is injected (covers both lifecycle and direct calls)\n\t\tif (this.pict.CSSMap)\n\t\t{\n\t\t\tthis.pict.CSSMap.injectCSS();\n\t\t}\n\t\tthis._renderer.render(this);\n\t\tthis._renderer.wireEvents(this);\n\t\tthis.initialRenderComplete = true;\n\t}\n\n\t// --- Data Marshaling ---\n\n\tmarshalToView()\n\t{\n\t\tsuper.marshalToView();\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\tmarshalFromView()\n\t{\n\t\tsuper.marshalFromView();\n\t\tthis._writeSelectionToAddress();\n\t}\n\n\t// --- Public API ---\n\n\t/**\n\t * Change the orientation and re-render.\n\t *\n\t * @param {string} pOrientation - \"vertical\" or \"horizontal\"\n\t */\n\tsetOrientation(pOrientation)\n\t{\n\t\tif (pOrientation !== 'vertical' && pOrientation !== 'horizontal')\n\t\t{\n\t\t\tthis.log.warn(`PICT-Histogram invalid orientation: ${pOrientation}`);\n\t\t\treturn;\n\t\t}\n\t\tthis.options.Orientation = pOrientation;\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\t/**\n\t * Change the render mode and re-render.\n\t *\n\t * @param {string} pRenderMode - \"browser\", \"consoleui\", or \"cli\"\n\t */\n\tsetRenderMode(pRenderMode)\n\t{\n\t\tthis.options.RenderMode = pRenderMode;\n\t\tthis._renderer = this._resolveRenderer();\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\t/**\n\t * Convenience: get the text representation (useful for CLI/consoleui).\n\t *\n\t * @returns {string}\n\t */\n\ttoText()\n\t{\n\t\tif (this.options.Orientation === 'vertical')\n\t\t{\n\t\t\treturn libRendererConsoleUI.renderVertical(this);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn libRendererConsoleUI.renderHorizontal(this);\n\t\t}\n\t}\n}\n\nmodule.exports = PictSectionHistogram;\n\nmodule.exports.default_configuration = _DefaultConfiguration;\nmodule.exports.renderers = {\n\tbrowser: libRendererBrowser,\n\tconsoleui: libRendererConsoleUI,\n\tcli: libRendererCLI\n};\n\n},{\"./Pict-Section-Histogram-DefaultConfiguration.js\":7,\"./renderers/Pict-Histogram-Renderer-Browser.js\":9,\"./renderers/Pict-Histogram-Renderer-CLI.js\":10,\"./renderers/Pict-Histogram-Renderer-ConsoleUI.js\":11,\"pict-view\":13}],9:[function(require,module,exports){\n/**\n * Browser renderer for pict-section-histogram.\n *\n * Renders the histogram as HTML/CSS elements using the Pict ContentAssignment\n * pipeline. Also wires up interactive selection (click, drag-slider) via\n * DOM event listeners.\n *\n * @module Pict-Histogram-Renderer-Browser\n */\n\n/**\n * Build the HTML string for a single bar group (bar + optional labels).\n *\n * @param {object} pBin - The bin data { Label, Value, ... }\n * @param {number} pIndex - Index of the bin\n * @param {number} pBarSize - Computed bar size in pixels\n * @param {object} pOptions - View options\n * @param {boolean} pIsSelected - Whether this bin is selected\n * @param {boolean} pInRange - Whether this bin is inside the range selection\n * @param {number} pLabelWidth - Fixed label width in pixels (horizontal mode)\n * @returns {string} HTML fragment\n */\nfunction buildBarGroupHTML(pBin, pIndex, pBarSize, pOptions, pIsSelected, pInRange, pLabelWidth)\n{\n\tlet tmpLabel = pBin[pOptions.LabelProperty] || '';\n\tlet tmpValue = pBin[pOptions.ValueProperty] || 0;\n\tlet tmpVertical = (pOptions.Orientation === 'vertical');\n\tlet tmpBarColor = pIsSelected ? pOptions.SelectedBarColor\n\t\t: pInRange ? pOptions.SelectionRangeColor\n\t\t: pOptions.BarColor;\n\n\tlet tmpSelectableClass = pOptions.Selectable ? ' pict-histogram-selectable' : '';\n\tlet tmpSelectedClass = pIsSelected ? ' pict-histogram-selected' : '';\n\tlet tmpInRangeClass = pInRange ? ' pict-histogram-in-range' : '';\n\n\tlet tmpBarStyle = '';\n\tif (tmpVertical)\n\t{\n\t\ttmpBarStyle = `height:${pBarSize}px;width:${pOptions.BarThickness}px;background-color:${tmpBarColor};`;\n\t}\n\telse\n\t{\n\t\ttmpBarStyle = `width:${pBarSize}px;height:${pOptions.BarThickness}px;background-color:${tmpBarColor};`;\n\t}\n\n\tlet tmpGroupWidth = pOptions.BarThickness + pOptions.BarGap;\n\tlet tmpGroupStyle = '';\n\tif (tmpVertical)\n\t{\n\t\ttmpGroupStyle = `margin:0 ${pOptions.BarGap / 2}px;width:${tmpGroupWidth}px;`;\n\t}\n\telse\n\t{\n\t\ttmpGroupStyle = `margin:${pOptions.BarGap / 2}px 0;`;\n\t}\n\n\tlet tmpHTML = `<div class=\"pict-histogram-bar-group\" style=\"${tmpGroupStyle}\" data-histogram-index=\"${pIndex}\">`;\n\n\tif (tmpVertical)\n\t{\n\t\t// Value label above bar\n\t\tif (pOptions.ShowValues)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-value-label\" style=\"width:${tmpGroupWidth}px;\">${tmpValue}</div>`;\n\t\t}\n\t\t// Bar\n\t\ttmpHTML += `<div class=\"pict-histogram-bar${tmpSelectableClass}${tmpSelectedClass}${tmpInRangeClass}\" style=\"${tmpBarStyle}\" data-histogram-index=\"${pIndex}\"></div>`;\n\t\t// Bin label below bar\n\t\tif (pOptions.ShowLabels)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-bin-label\" style=\"width:${tmpGroupWidth}px;\">${tmpLabel}</div>`;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Bin label to the left (fixed width so bars align)\n\t\tif (pOptions.ShowLabels)\n\t\t{\n\t\t\tlet tmpLabelStyle = pLabelWidth ? `width:${pLabelWidth}px;min-width:${pLabelWidth}px;` : '';\n\t\t\ttmpHTML += `<div class=\"pict-histogram-bin-label\" style=\"${tmpLabelStyle}\">${tmpLabel}</div>`;\n\t\t}\n\t\t// Bar\n\t\ttmpHTML += `<div class=\"pict-histogram-bar${tmpSelectableClass}${tmpSelectedClass}${tmpInRangeClass}\" style=\"${tmpBarStyle}\" data-histogram-index=\"${pIndex}\"></div>`;\n\t\t// Value label to the right\n\t\tif (pOptions.ShowValues)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-value-label\">${tmpValue}</div>`;\n\t\t}\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Build the HTML for the range-slider overlay (used in \"range\" selection mode).\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} HTML fragment\n */\nfunction buildRangeSliderHTML(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '';\n\t}\n\n\tlet tmpRangeStart = pView._selectionRangeStart;\n\tlet tmpRangeEnd = pView._selectionRangeEnd;\n\tlet tmpMax = tmpBins.length - 1;\n\n\t// Calculate percentage positions for the handles\n\tlet tmpStartPct = (tmpMax > 0) ? ((tmpRangeStart / tmpMax) * 100) : 0;\n\tlet tmpEndPct = (tmpMax > 0) ? ((tmpRangeEnd / tmpMax) * 100) : 100;\n\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\n\tlet tmpHTML = '<div class=\"pict-histogram-range-slider-container\">';\n\ttmpHTML += '<div class=\"pict-histogram-range-track\"></div>';\n\n\tif (tmpVertical)\n\t{\n\t\ttmpHTML += `<div class=\"pict-histogram-range-fill\" style=\"left:${tmpStartPct}%;right:${100 - tmpEndPct}%;\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-start\" tabindex=\"0\" style=\"left:${tmpStartPct}%;\" data-handle=\"start\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-end\" tabindex=\"0\" style=\"left:${tmpEndPct}%;\" data-handle=\"end\"></div>`;\n\t}\n\telse\n\t{\n\t\ttmpHTML += `<div class=\"pict-histogram-range-fill\" style=\"top:${tmpStartPct}%;bottom:${100 - tmpEndPct}%;\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-start\" tabindex=\"0\" style=\"top:${tmpStartPct}%;\" data-handle=\"start\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-end\" tabindex=\"0\" style=\"top:${tmpEndPct}%;\" data-handle=\"end\"></div>`;\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Render the full histogram into the target element.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\tpView.services.ContentAssignment.assignContent(\n\t\t\tpView.options.TargetElementAddress,\n\t\t\t'<div class=\"pict-histogram-container\"><em>No histogram data</em></div>'\n\t\t);\n\t\treturn;\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][pView.options.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\tlet tmpOrientationClass = tmpVertical ? 'pict-histogram-vertical' : 'pict-histogram-horizontal';\n\n\t// For horizontal mode, measure the longest label so all labels share the same width\n\tlet tmpLabelWidth = 0;\n\tif (!tmpVertical && pView.options.ShowLabels)\n\t{\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][pView.options.LabelProperty] || '');\n\t\t\t// Approximate character width at 11px font: ~6.5px per character\n\t\t\tlet tmpEstWidth = tmpLabel.length * 6.5 + 8;\n\t\t\tif (tmpEstWidth > tmpLabelWidth)\n\t\t\t{\n\t\t\t\ttmpLabelWidth = tmpEstWidth;\n\t\t\t}\n\t\t}\n\t\ttmpLabelWidth = Math.max(tmpLabelWidth, 40);\n\t}\n\n\tlet tmpHTML = `<div class=\"pict-histogram-container ${tmpOrientationClass}\">`;\n\ttmpHTML += `<div class=\"pict-histogram-chart ${tmpOrientationClass}\">`;\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][pView.options.ValueProperty] || 0;\n\t\tlet tmpBarSize = Math.round((tmpVal / tmpMaxValue) * pView.options.MaxBarSize);\n\t\tif (tmpVal > 0 && tmpBarSize < 1)\n\t\t{\n\t\t\ttmpBarSize = 1;\n\t\t}\n\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\n\t\ttmpHTML += buildBarGroupHTML(tmpBins[i], i, tmpBarSize, pView.options, tmpIsSelected, tmpInRange, tmpLabelWidth);\n\t}\n\n\ttmpHTML += '</div>';\n\n\t// Range slider for \"range\" selection mode\n\tif (pView.options.Selectable && pView.options.SelectionMode === 'range')\n\t{\n\t\ttmpHTML += buildRangeSliderHTML(pView);\n\t}\n\n\ttmpHTML += '</div>';\n\n\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpHTML);\n}\n\n/**\n * Wire up DOM event listeners for interactivity (click selection, range drag).\n *\n * @param {object} pView - The histogram view instance\n */\nfunction wireEvents(pView)\n{\n\tif (!pView.options.Selectable)\n\t{\n\t\treturn;\n\t}\n\n\tlet tmpTargetElementSet = pView.services.ContentAssignment.getElement(pView.options.TargetElementAddress);\n\tif (!tmpTargetElementSet || tmpTargetElementSet.length < 1)\n\t{\n\t\treturn;\n\t}\n\tlet tmpContainer = tmpTargetElementSet[0];\n\tif (!tmpContainer)\n\t{\n\t\treturn;\n\t}\n\n\t// --- Bar click selection (single / multiple modes) ---\n\tif (pView.options.SelectionMode === 'single' || pView.options.SelectionMode === 'multiple')\n\t{\n\t\tlet tmpBars = tmpContainer.querySelectorAll('.pict-histogram-bar[data-histogram-index]');\n\t\tfor (let i = 0; i < tmpBars.length; i++)\n\t\t{\n\t\t\ttmpBars[i].addEventListener('click', (pEvent) =>\n\t\t\t{\n\t\t\t\tlet tmpIndex = parseInt(pEvent.currentTarget.getAttribute('data-histogram-index'), 10);\n\t\t\t\tif (isNaN(tmpIndex))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpView.handleBarClick(tmpIndex);\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Range slider drag ---\n\tif (pView.options.SelectionMode === 'range')\n\t{\n\t\t// Also allow clicking bars to move nearest handle\n\t\tlet tmpBars = tmpContainer.querySelectorAll('.pict-histogram-bar[data-histogram-index]');\n\t\tfor (let i = 0; i < tmpBars.length; i++)\n\t\t{\n\t\t\ttmpBars[i].addEventListener('click', (pEvent) =>\n\t\t\t{\n\t\t\t\tlet tmpIndex = parseInt(pEvent.currentTarget.getAttribute('data-histogram-index'), 10);\n\t\t\t\tif (isNaN(tmpIndex))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpView.handleRangeBarClick(tmpIndex);\n\t\t\t});\n\t\t}\n\n\t\tlet tmpHandles = tmpContainer.querySelectorAll('.pict-histogram-range-handle');\n\t\tfor (let i = 0; i < tmpHandles.length; i++)\n\t\t{\n\t\t\twireRangeHandle(pView, tmpHandles[i], tmpContainer);\n\t\t}\n\t}\n}\n\n/**\n * Wire drag behavior on a single range handle element.\n *\n * @param {object} pView - The histogram view instance\n * @param {Element} pHandle - The handle DOM element\n * @param {Element} pContainer - The histogram container element\n */\nfunction wireRangeHandle(pView, pHandle, pContainer)\n{\n\tlet tmpHandleType = pHandle.getAttribute('data-handle'); // \"start\" or \"end\"\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\n\tlet tmpDragging = false;\n\n\tfunction getSliderBounds()\n\t{\n\t\t// Re-query from pContainer every time because renderHistogram() replaces\n\t\t// the inner HTML, detaching any previously-captured slider element.\n\t\tlet tmpSlider = pContainer.querySelector('.pict-histogram-range-slider-container');\n\t\tif (!tmpSlider)\n\t\t{\n\t\t\treturn { start: 0, size: 1 };\n\t\t}\n\t\tlet tmpRect = tmpSlider.getBoundingClientRect();\n\t\tif (tmpVertical)\n\t\t{\n\t\t\treturn { start: tmpRect.left, size: tmpRect.width || 1 };\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn { start: tmpRect.top, size: tmpRect.height || 1 };\n\t\t}\n\t}\n\n\tfunction onPointerMove(pEvent)\n\t{\n\t\tif (!tmpDragging)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBins = pView.getBins();\n\t\tif (!tmpBins || tmpBins.length === 0)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBounds = getSliderBounds();\n\t\tlet tmpPos = tmpVertical ? pEvent.clientX : pEvent.clientY;\n\t\tlet tmpPct = (tmpPos - tmpBounds.start) / tmpBounds.size;\n\t\ttmpPct = Math.max(0, Math.min(1, tmpPct));\n\n\t\tlet tmpIndex = Math.round(tmpPct * (tmpBins.length - 1));\n\n\t\tif (tmpHandleType === 'start')\n\t\t{\n\t\t\tif (tmpIndex > pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpIndex = pView._selectionRangeEnd;\n\t\t\t}\n\t\t\tpView._selectionRangeStart = tmpIndex;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (tmpIndex < pView._selectionRangeStart)\n\t\t\t{\n\t\t\t\ttmpIndex = pView._selectionRangeStart;\n\t\t\t}\n\t\t\tpView._selectionRangeEnd = tmpIndex;\n\t\t}\n\n\t\tpView._syncSelectionFromRange();\n\t\tpView.renderHistogram();\n\t}\n\n\tfunction onPointerUp()\n\t{\n\t\tif (!tmpDragging)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\ttmpDragging = false;\n\t\tif (typeof (document) !== 'undefined')\n\t\t{\n\t\t\tdocument.removeEventListener('mousemove', onPointerMove);\n\t\t\tdocument.removeEventListener('mouseup', onPointerUp);\n\t\t}\n\t}\n\n\tpHandle.addEventListener('mousedown', (pEvent) =>\n\t{\n\t\tpEvent.preventDefault();\n\t\ttmpDragging = true;\n\t\tif (typeof (document) !== 'undefined')\n\t\t{\n\t\t\tdocument.addEventListener('mousemove', onPointerMove);\n\t\t\tdocument.addEventListener('mouseup', onPointerUp);\n\t\t}\n\t});\n}\n\nmodule.exports = { render, wireEvents };\n\n},{}],10:[function(require,module,exports){\n(function (process){(function (){\n/**\n * CLI renderer for pict-section-histogram.\n *\n * Renders the histogram as ANSI-colored text written directly to stdout\n * (or through the Pict ContentAssignment pipeline if available).\n *\n * This mode is intended for command-line tools that print histogram output\n * without a full terminal UI framework.\n *\n * @module Pict-Histogram-Renderer-CLI\n */\n\n// ANSI color codes (basic 16-color)\nconst ANSI_COLORS = {\n\t'black': '\\x1b[30m',\n\t'red': '\\x1b[31m',\n\t'green': '\\x1b[32m',\n\t'yellow': '\\x1b[33m',\n\t'blue': '\\x1b[34m',\n\t'magenta': '\\x1b[35m',\n\t'cyan': '\\x1b[36m',\n\t'white': '\\x1b[37m',\n\t'reset': '\\x1b[0m',\n\t'bold': '\\x1b[1m',\n\t'dim': '\\x1b[2m'\n};\n\n/**\n * Map a CSS-ish color string to the nearest ANSI color.\n *\n * @param {string} pColor - A color string (name or hex)\n * @returns {string} ANSI escape code\n */\nfunction colorToAnsi(pColor)\n{\n\tif (!pColor)\n\t{\n\t\treturn ANSI_COLORS.blue;\n\t}\n\n\tlet tmpLower = pColor.toLowerCase();\n\n\t// Direct name match\n\tif (ANSI_COLORS[tmpLower])\n\t{\n\t\treturn ANSI_COLORS[tmpLower];\n\t}\n\n\t// Simple hex-to-nearest mapping\n\tif (tmpLower.charAt(0) === '#' && tmpLower.length >= 7)\n\t{\n\t\tlet tmpR = parseInt(tmpLower.substring(1, 3), 16);\n\t\tlet tmpG = parseInt(tmpLower.substring(3, 5), 16);\n\t\tlet tmpB = parseInt(tmpLower.substring(5, 7), 16);\n\n\t\t// Pick nearest basic color\n\t\tif (tmpG > tmpR && tmpG > tmpB)\n\t\t{\n\t\t\treturn ANSI_COLORS.green;\n\t\t}\n\t\tif (tmpR > tmpG && tmpR > tmpB)\n\t\t{\n\t\t\treturn ANSI_COLORS.red;\n\t\t}\n\t\tif (tmpB > tmpR && tmpB > tmpG)\n\t\t{\n\t\t\treturn ANSI_COLORS.blue;\n\t\t}\n\t\tif (tmpR > 200 && tmpG > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.yellow;\n\t\t}\n\t\tif (tmpR > 200 && tmpB > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.magenta;\n\t\t}\n\t\tif (tmpG > 200 && tmpB > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.cyan;\n\t\t}\n\t}\n\n\treturn ANSI_COLORS.blue;\n}\n\n/**\n * Render a vertical CLI histogram.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The ANSI text output\n */\nfunction renderVertical(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpHeight = tmpOptions.TextHeight || 15;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\tlet tmpBarColor = colorToAnsi(tmpOptions.BarColor);\n\tlet tmpSelectedColor = colorToAnsi(tmpOptions.SelectedBarColor);\n\tlet tmpRangeColor = colorToAnsi(tmpOptions.SelectionRangeColor);\n\tlet tmpReset = ANSI_COLORS.reset;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)\\n';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpValueAxisWidth = String(tmpMaxValue).length + 1;\n\tlet tmpLines = [];\n\n\tfor (let tmpRow = tmpHeight; tmpRow >= 1; tmpRow--)\n\t{\n\t\tlet tmpLine = '';\n\n\t\t// Axis labels\n\t\tif (tmpRow === tmpHeight)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft(String(tmpMaxValue), tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse if (tmpRow === 1)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft('0', tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse if (tmpRow === Math.ceil(tmpHeight / 2))\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft(String(Math.round(tmpMaxValue / 2)), tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft('', tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\t\tlet tmpBarHeight = (tmpVal / tmpMaxValue) * tmpHeight;\n\t\t\tlet tmpFullRows = Math.floor(tmpBarHeight);\n\t\t\tlet tmpFraction = tmpBarHeight - tmpFullRows;\n\n\t\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\t\tlet tmpColor = tmpIsSelected ? tmpSelectedColor : (tmpInRange ? tmpRangeColor : tmpBarColor);\n\n\t\t\tlet tmpChar = ' ';\n\t\t\tif (tmpRow <= tmpFullRows)\n\t\t\t{\n\t\t\t\ttmpChar = tmpBarChar;\n\t\t\t}\n\t\t\telse if (tmpRow === tmpFullRows + 1 && tmpFraction > 0)\n\t\t\t{\n\t\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\t\ttmpChar = tmpPartials[tmpPartialIndex];\n\t\t\t}\n\n\t\t\tif (tmpChar !== ' ')\n\t\t\t{\n\t\t\t\ttmpLine += ' ' + tmpColor + tmpChar + tmpChar + tmpChar + tmpReset;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpLine += ' ';\n\t\t\t}\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Bottom axis\n\tlet tmpAxisLine = ANSI_COLORS.dim + padLeft('', tmpValueAxisWidth) + '+';\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\ttmpAxisLine += '----';\n\t}\n\ttmpAxisLine += tmpReset;\n\ttmpLines.push(tmpAxisLine);\n\n\t// Labels\n\tif (tmpOptions.ShowLabels)\n\t{\n\t\tlet tmpLabelLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\t\ttmpLabelLine += padCenter(tmpLabel.substring(0, 4), 4);\n\t\t}\n\t\ttmpLines.push(tmpLabelLine);\n\t}\n\n\t// Range selection info\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpStart = pView._selectionRangeStart;\n\t\tlet tmpEnd = pView._selectionRangeEnd;\n\t\tlet tmpStartLabel = tmpBins[tmpStart] ? tmpBins[tmpStart][tmpOptions.LabelProperty] : tmpStart;\n\t\tlet tmpEndLabel = tmpBins[tmpEnd] ? tmpBins[tmpEnd][tmpOptions.LabelProperty] : tmpEnd;\n\t\ttmpLines.push('');\n\t\ttmpLines.push(ANSI_COLORS.bold + ' Selection: ' + tmpStartLabel + ' - ' + tmpEndLabel + tmpReset);\n\t}\n\n\treturn tmpLines.join('\\n') + '\\n';\n}\n\n/**\n * Render a horizontal CLI histogram.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The ANSI text output\n */\nfunction renderHorizontal(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpWidth = tmpOptions.TextWidth || 60;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpBarColor = colorToAnsi(tmpOptions.BarColor);\n\tlet tmpSelectedColor = colorToAnsi(tmpOptions.SelectedBarColor);\n\tlet tmpRangeColor = colorToAnsi(tmpOptions.SelectionRangeColor);\n\tlet tmpReset = ANSI_COLORS.reset;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)\\n';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tlet tmpMaxLabelLen = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tif (tmpLabel.length > tmpMaxLabelLen)\n\t\t{\n\t\t\ttmpMaxLabelLen = tmpLabel.length;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpLabelWidth = Math.min(tmpMaxLabelLen, 12);\n\tlet tmpValueWidth = String(tmpMaxValue).length;\n\tlet tmpBarWidth = tmpWidth - tmpLabelWidth - tmpValueWidth - 4;\n\tif (tmpBarWidth < 10)\n\t{\n\t\ttmpBarWidth = 10;\n\t}\n\n\tlet tmpLines = [];\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tlet tmpBarLen = Math.round((tmpVal / tmpMaxValue) * tmpBarWidth);\n\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\tlet tmpColor = tmpIsSelected ? tmpSelectedColor : (tmpInRange ? tmpRangeColor : tmpBarColor);\n\n\t\tlet tmpBar = '';\n\t\tfor (let j = 0; j < tmpBarLen; j++)\n\t\t{\n\t\t\ttmpBar += tmpBarChar;\n\t\t}\n\n\t\tlet tmpLine = ANSI_COLORS.dim + padRight(tmpLabel.substring(0, tmpLabelWidth), tmpLabelWidth) + ' |' + tmpReset;\n\t\ttmpLine += tmpColor + tmpBar + tmpReset;\n\t\ttmpLine += ' ' + tmpVal;\n\n\t\tif (tmpIsSelected)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.bold + ' *' + tmpReset;\n\t\t}\n\t\telse if (tmpInRange)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + ' ~' + tmpReset;\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Range info\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpStart = pView._selectionRangeStart;\n\t\tlet tmpEnd = pView._selectionRangeEnd;\n\t\tlet tmpStartLabel = tmpBins[tmpStart] ? tmpBins[tmpStart][tmpOptions.LabelProperty] : tmpStart;\n\t\tlet tmpEndLabel = tmpBins[tmpEnd] ? tmpBins[tmpEnd][tmpOptions.LabelProperty] : tmpEnd;\n\t\ttmpLines.push('');\n\t\ttmpLines.push(ANSI_COLORS.bold + ' Selection: ' + tmpStartLabel + ' - ' + tmpEndLabel + tmpReset);\n\t}\n\n\treturn tmpLines.join('\\n') + '\\n';\n}\n\n/**\n * Render in CLI mode. Writes to ContentAssignment if available, otherwise\n * falls back to process.stdout.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpText;\n\tif (pView.options.Orientation === 'vertical')\n\t{\n\t\ttmpText = renderVertical(pView);\n\t}\n\telse\n\t{\n\t\ttmpText = renderHorizontal(pView);\n\t}\n\n\t// Try ContentAssignment first (might be mocked in tests or bridged)\n\tif (pView.services && pView.services.ContentAssignment)\n\t{\n\t\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpText);\n\t}\n\telse if (typeof (process) !== 'undefined' && process.stdout)\n\t{\n\t\tprocess.stdout.write(tmpText);\n\t}\n}\n\n// No interactive events in CLI mode\nfunction wireEvents()\n{\n\t// No-op for CLI\n}\n\n// --- Utility ---\n\nfunction padLeft(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = ' ' + tmpStr;\n\t}\n\treturn tmpStr;\n}\n\nfunction padRight(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = tmpStr + ' ';\n\t}\n\treturn tmpStr;\n}\n\nfunction padCenter(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = (tmpStr.length % 2 === 0) ? (tmpStr + ' ') : (' ' + tmpStr);\n\t}\n\treturn tmpStr;\n}\n\nmodule.exports = { render, wireEvents, renderVertical, renderHorizontal, colorToAnsi, ANSI_COLORS };\n\n}).call(this)}).call(this,require('_process'))\n\n},{\"_process\":14}],11:[function(require,module,exports){\n/**\n * Console UI (blessed) renderer for pict-section-histogram.\n *\n * Renders the histogram as text art through the Pict ContentAssignment\n * pipeline, suitable for blessed/ncurses terminal UI widgets.\n *\n * The output is assigned via ContentAssignment so the pict-terminalui\n * bridge (customAssignFunction) can project it into blessed boxes.\n *\n * @module Pict-Histogram-Renderer-ConsoleUI\n */\n\n/**\n * Build a vertical text histogram.\n *\n * Each column is one bar. Rows go from top (max value) to bottom (0).\n * Uses block characters for fractional rows.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The rendered text block\n */\nfunction renderVertical(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpHeight = tmpOptions.TextHeight || 15;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\tlet tmpEmptyChar = tmpOptions.EmptyCharacter;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\t// Determine label width for the value axis\n\tlet tmpValueAxisWidth = String(tmpMaxValue).length + 1;\n\n\t// Build the grid top-down\n\tlet tmpLines = [];\n\n\tfor (let tmpRow = tmpHeight; tmpRow >= 1; tmpRow--)\n\t{\n\t\tlet tmpLine = '';\n\n\t\t// Value axis label (only on a few rows)\n\t\tif (tmpRow === tmpHeight)\n\t\t{\n\t\t\ttmpLine += padLeft(String(tmpMaxValue), tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse if (tmpRow === 1)\n\t\t{\n\t\t\ttmpLine += padLeft('0', tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse if (tmpRow === Math.ceil(tmpHeight / 2))\n\t\t{\n\t\t\ttmpLine += padLeft(String(Math.round(tmpMaxValue / 2)), tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLine += padLeft('', tmpValueAxisWidth) + '|';\n\t\t}\n\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\t\tlet tmpBarHeight = (tmpVal / tmpMaxValue) * tmpHeight;\n\t\t\tlet tmpFullRows = Math.floor(tmpBarHeight);\n\t\t\tlet tmpFraction = tmpBarHeight - tmpFullRows;\n\n\t\t\tlet tmpChar = tmpEmptyChar;\n\t\t\tif (tmpRow <= tmpFullRows)\n\t\t\t{\n\t\t\t\ttmpChar = tmpBarChar;\n\t\t\t}\n\t\t\telse if (tmpRow === tmpFullRows + 1 && tmpFraction > 0)\n\t\t\t{\n\t\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\t\ttmpChar = tmpPartials[tmpPartialIndex];\n\t\t\t}\n\n\t\t\t// Mark selected bins\n\t\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\n\t\t\tif (tmpIsSelected && tmpChar !== tmpEmptyChar)\n\t\t\t{\n\t\t\t\ttmpChar = '*';\n\t\t\t}\n\t\t\telse if (tmpInRange && tmpChar !== tmpEmptyChar)\n\t\t\t{\n\t\t\t\ttmpChar = '#';\n\t\t\t}\n\n\t\t\t// Each bar is 3 chars wide with 1 char gap\n\t\t\ttmpLine += ' ' + tmpChar + tmpChar + tmpChar;\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Bottom axis\n\tlet tmpAxisLine = padLeft('', tmpValueAxisWidth) + '+';\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\ttmpAxisLine += '----';\n\t}\n\ttmpLines.push(tmpAxisLine);\n\n\t// Labels row\n\tif (tmpOptions.ShowLabels)\n\t{\n\t\tlet tmpLabelLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\t\ttmpLabelLine += padCenter(tmpLabel.substring(0, 4), 4);\n\t\t}\n\t\ttmpLines.push(tmpLabelLine);\n\t}\n\n\t// Selection range indicator\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpRangeLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tif (i === pView._selectionRangeStart)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' [ ';\n\t\t\t}\n\t\t\telse if (i === pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' ] ';\n\t\t\t}\n\t\t\telse if (i > pView._selectionRangeStart && i < pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' - ';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' ';\n\t\t\t}\n\t\t}\n\t\ttmpLines.push(tmpRangeLine);\n\t}\n\n\treturn tmpLines.join('\\n');\n}\n\n/**\n * Build a horizontal text histogram.\n *\n * Each row is one bar growing rightward.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The rendered text block\n */\nfunction renderHorizontal(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpWidth = tmpOptions.TextWidth || 60;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tlet tmpMaxLabelLen = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tif (tmpLabel.length > tmpMaxLabelLen)\n\t\t{\n\t\t\ttmpMaxLabelLen = tmpLabel.length;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpLabelWidth = Math.min(tmpMaxLabelLen, 12);\n\tlet tmpBarWidth = tmpWidth - tmpLabelWidth - 2; // space for \" |\"\n\tif (tmpBarWidth < 10)\n\t{\n\t\ttmpBarWidth = 10;\n\t}\n\n\tlet tmpLines = [];\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tlet tmpBarLen = (tmpVal / tmpMaxValue) * tmpBarWidth;\n\t\tlet tmpFullChars = Math.floor(tmpBarLen);\n\t\tlet tmpFraction = tmpBarLen - tmpFullChars;\n\n\t\tlet tmpBar = '';\n\t\tfor (let j = 0; j < tmpFullChars; j++)\n\t\t{\n\t\t\ttmpBar += tmpBarChar;\n\t\t}\n\t\tif (tmpFraction > 0 && tmpFullChars < tmpBarWidth)\n\t\t{\n\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\ttmpBar += tmpPartials[tmpPartialIndex];\n\t\t}\n\n\t\t// Mark selected\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\tlet tmpMarker = tmpIsSelected ? '*' : (tmpInRange ? '~' : '');\n\n\t\tlet tmpValueStr = tmpOptions.ShowValues ? (' ' + tmpVal) : '';\n\t\tlet tmpLine = padRight(tmpLabel.substring(0, tmpLabelWidth), tmpLabelWidth) + ' |' + tmpBar + tmpValueStr + tmpMarker;\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Range indicator for range selection\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\ttmpLines.push('');\n\t\ttmpLines.push(padRight('', tmpLabelWidth) + ' Range: [' + pView._selectionRangeStart + ' - ' + pView._selectionRangeEnd + ']');\n\t}\n\n\treturn tmpLines.join('\\n');\n}\n\n/**\n * Render via ContentAssignment for consoleui mode.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpText;\n\tif (pView.options.Orientation === 'vertical')\n\t{\n\t\ttmpText = renderVertical(pView);\n\t}\n\telse\n\t{\n\t\ttmpText = renderHorizontal(pView);\n\t}\n\n\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpText);\n}\n\n// No interactive events for consoleui — input is handled by the blessed widget layer\nfunction wireEvents()\n{\n\t// No-op for consoleui\n}\n\n// --- Utility ---\n\nfunction padLeft(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = ' ' + tmpStr;\n\t}\n\treturn tmpStr;\n}\n\nfunction padRight(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = tmpStr + ' ';\n\t}\n\treturn tmpStr;\n}\n\nfunction padCenter(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = (tmpStr.length % 2 === 0) ? (tmpStr + ' ') : (' ' + tmpStr);\n\t}\n\treturn tmpStr;\n}\n\nmodule.exports = { render, wireEvents, renderVertical, renderHorizontal };\n\n},{}],12:[function(require,module,exports){\nmodule.exports={\n \"name\": \"pict-view\",\n \"version\": \"1.0.67\",\n \"description\": \"Pict View Base Class\",\n \"main\": \"source/Pict-View.js\",\n \"scripts\": {\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"start\": \"node source/Pict-View.js\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-view-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-view-dev -p 30001:8080 -p 38086:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-view\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-view-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-view-dev /bin/bash\",\n \"types\": \"tsc -p .\",\n \"lint\": \"eslint source/**\"\n },\n \"types\": \"types/source/Pict-View.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-view.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-view/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-view#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.1\",\n \"browser-env\": \"^3.3.0\",\n \"eslint\": \"^9.39.1\",\n \"pict\": \"^1.0.348\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"dependencies\": {\n \"fable\": \"^3.1.63\",\n \"fable-serviceproviderbase\": \"^3.0.19\"\n }\n}\n\n},{}],13:[function(require,module,exports){\n\nconst libFableServiceBase = require('fable-serviceproviderbase');\n\nconst libPackage = require('../package.json');\n\nconst defaultPictViewSettings = (\n\t{\n\t\tDefaultRenderable: false,\n\t\tDefaultDestinationAddress: false,\n\t\tDefaultTemplateRecordAddress: false,\n\n\t\tViewIdentifier: false,\n\n\t\t// If this is set to true, when the App initializes this will.\n\t\t// After the App initializes, initialize will be called as soon as it's added.\n\t\tAutoInitialize: true,\n\t\tAutoInitializeOrdinal: 0,\n\n\t\t// If this is set to true, when the App autorenders (on load) this will.\n\t\t// After the App initializes, render will be called as soon as it's added.\n\t\tAutoRender: true,\n\t\tAutoRenderOrdinal: 0,\n\n\t\tAutoSolveWithApp: true,\n\t\tAutoSolveOrdinal: 0,\n\n\t\tCSSHash: false,\n\t\tCSS: false,\n\t\tCSSProvider: false,\n\t\tCSSPriority: 500,\n\n\t\tTemplates: [],\n\n\t\tDefaultTemplates: [],\n\n\t\tRenderables: [],\n\n\t\tManifests: {}\n\t});\n\n/** @typedef {(error?: Error) => void} ErrorCallback */\n/** @typedef {number | boolean} PictTimestamp */\n\n/**\n * @typedef {'replace' | 'append' | 'prepend' | 'append_once' | 'virtual-assignment'} RenderMethod\n */\n/**\n * @typedef {Object} Renderable\n *\n * @property {string} RenderableHash - A unique hash for the renderable.\n * @property {string} TemplateHash - The hash of the template to use for rendering this renderable.\n * @property {string} [DefaultTemplateRecordAddress] - The default address for resolving the data record for this renderable.\n * @property {string} [ContentDestinationAddress] - The default address (DOM CSS selector) for rendering the content of this renderable.\n * @property {RenderMethod} [RenderMethod=replace] - The method to use when projecting the renderable to the DOM ('replace', 'append', 'prepend', 'append_once', 'virtual-assignment').\n * @property {string} [TestAddress] - The address to use for testing the renderable.\n * @property {string} [TransactionHash] - The transaction hash for the root renderable.\n * @property {string} [RootRenderableViewHash] - The hash of the root renderable.\n * @property {string} [Content] - The rendered content for this renderable, if applicable.\n */\n\n/**\n * Represents a view in the Pict ecosystem.\n */\nclass PictView extends libFableServiceBase\n{\n\t/**\n\t * @param {any} pFable - The Fable object that this service is attached to.\n\t * @param {any} [pOptions] - (optional) The options for this service.\n\t * @param {string} [pServiceHash] - (optional) The hash of the service.\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t// Intersect default options, parent constructor, service information\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictViewSettings)), pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\t\t//FIXME: add types to fable and ancillaries\n\t\t/** @type {any} */\n\t\tthis.fable;\n\t\t/** @type {any} */\n\t\tthis.options;\n\t\t/** @type {String} */\n\t\tthis.UUID;\n\t\t/** @type {String} */\n\t\tthis.Hash;\n\t\t/** @type {any} */\n\t\tthis.log;\n\n\t\tconst tmpHashIsUUID = this.Hash === this.UUID;\n\t\t//NOTE: since many places are using the view UUID as the HTML element ID, we prefix it to avoid starting with a number\n\t\tthis.UUID = `V-${this.UUID}`;\n\t\tif (tmpHashIsUUID)\n\t\t{\n\t\t\tthis.Hash = this.UUID;\n\t\t}\n\n\t\tif (!this.options.ViewIdentifier)\n\t\t{\n\t\t\tthis.options.ViewIdentifier = `AutoViewID-${this.fable.getUUID()}`;\n\t\t}\n\t\tthis.serviceType = 'PictView';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\t\t// Convenience and consistency naming\n\t\t/** @type {import('pict') & { log: any, instantiateServiceProviderWithoutRegistration: (hash: String) => any, instantiateServiceProviderIfNotExists: (hash: string) => any, TransactionTracking: import('pict/types/source/services/Fable-Service-TransactionTracking') }} */\n\t\tthis.pict = this.fable;\n\t\t// Wire in the essential Pict application state\n\t\tthis.AppData = this.pict.AppData;\n\t\tthis.Bundle = this.pict.Bundle;\n\n\t\t/** @type {PictTimestamp} */\n\t\tthis.initializeTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastSolvedTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastRenderedTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastMarshalFromViewTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastMarshalToViewTimestamp = false;\n\n\t\tthis.pict.instantiateServiceProviderIfNotExists('TransactionTracking');\n\n\t\t// Load all templates from the array in the options\n\t\t// Templates are in the form of {Hash:'Some-Template-Hash',Template:'Template content',Source:'TemplateSource'}\n\t\tfor (let i = 0; i < this.options.Templates.length; i++)\n\t\t{\n\t\t\tlet tmpTemplate = this.options.Templates[i];\n\n\t\t\tif (!('Hash' in tmpTemplate) || !('Template' in tmpTemplate))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Template ${i} in the options array.`, tmpTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpTemplate.Source = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addTemplate(tmpTemplate.Hash, tmpTemplate.Template, tmpTemplate.Source);\n\t\t\t}\n\t\t}\n\n\t\t// Load all default templates from the array in the options\n\t\t// Templates are in the form of {Prefix:'',Postfix:'-List-Row',Template:'Template content',Source:'TemplateSourceString'}\n\t\tfor (let i = 0; i < this.options.DefaultTemplates.length; i++)\n\t\t{\n\t\t\tlet tmpDefaultTemplate = this.options.DefaultTemplates[i];\n\n\t\t\tif (!('Postfix' in tmpDefaultTemplate) || !('Template' in tmpDefaultTemplate))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Default Template ${i} in the options array.`, tmpDefaultTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpDefaultTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpDefaultTemplate.Source = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix, tmpDefaultTemplate.Postfix, tmpDefaultTemplate.Template, tmpDefaultTemplate.Source);\n\t\t\t}\n\t\t}\n\n\t\t// Load the CSS if it's available\n\t\tif (this.options.CSS)\n\t\t{\n\t\t\tlet tmpCSSHash = this.options.CSSHash ? this.options.CSSHash : `View-${this.options.ViewIdentifier}`;\n\t\t\tlet tmpCSSProvider = this.options.CSSProvider ? this.options.CSSProvider : tmpCSSHash;\n\t\t\tthis.pict.CSSMap.addCSS(tmpCSSHash, this.options.CSS, tmpCSSProvider, this.options.CSSPriority);\n\t\t}\n\n\t\t// Load all renderables\n\t\t// Renderables are launchable renderable instructions with templates\n\t\t// They look as such: {Identifier:'ContentEntry', TemplateHash:'Content-Entry-Section-Main', ContentDestinationAddress:'#ContentSection', RecordAddress:'AppData.Content.DefaultText', ManifestTransformation:'ManyfestHash', ManifestDestinationAddress:'AppData.Content.DataToTransformContent'}\n\t\t// The only parts that are necessary are Identifier and Template\n\t\t// A developer can then do render('ContentEntry') and it just kinda works. Or they can override the ContentDestinationAddress\n\t\t/** @type {Record<String, Renderable>} */\n\t\tthis.renderables = {};\n\t\tfor (let i = 0; i < this.options.Renderables.length; i++)\n\t\t{\n\t\t\t/** @type {Renderable} */\n\t\t\tlet tmpRenderable = this.options.Renderables[i];\n\t\t\tthis.addRenderable(tmpRenderable);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a renderable to the view.\n\t *\n\t * @param {string | Renderable} pRenderableHash - The hash of the renderable, or a renderable object.\n\t * @param {string} [pTemplateHash] - (optional) The hash of the template for the renderable.\n\t * @param {string} [pDefaultTemplateRecordAddress] - (optional) The default data address for the template.\n\t * @param {string} [pDefaultDestinationAddress] - (optional) The default destination address for the renderable.\n\t * @param {RenderMethod} [pRenderMethod=replace] - (optional) The method to use when rendering the renderable (ex. 'replace').\n\t */\n\taddRenderable(pRenderableHash, pTemplateHash, pDefaultTemplateRecordAddress, pDefaultDestinationAddress, pRenderMethod)\n\t{\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\n\t\tif (typeof(pRenderableHash) == 'object')\n\t\t{\n\t\t\t// The developer passed in the renderable as an object.\n\t\t\t// Use theirs instead!\n\t\t\ttmpRenderable = pRenderableHash;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/** @type {RenderMethod} */\n\t\t\tlet tmpRenderMethod = (typeof(pRenderMethod) !== 'string') ? pRenderMethod : 'replace';\n\t\t\ttmpRenderable = (\n\t\t\t\t{\n\t\t\t\t\tRenderableHash: pRenderableHash,\n\t\t\t\t\tTemplateHash: pTemplateHash,\n\t\t\t\t\tDefaultTemplateRecordAddress: pDefaultTemplateRecordAddress,\n\t\t\t\t\tContentDestinationAddress: pDefaultDestinationAddress,\n\t\t\t\t\tRenderMethod: tmpRenderMethod\n\t\t\t\t});\n\t\t}\n\n\t\tif ((typeof(tmpRenderable.RenderableHash) != 'string') || (typeof(tmpRenderable.TemplateHash) != 'string'))\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Renderable; RenderableHash or TemplateHash are invalid.`, tmpRenderable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} adding renderable [${tmpRenderable.RenderableHash}] pointed to template ${tmpRenderable.TemplateHash}.`);\n\t\t\t}\n\n\t\t\tthis.renderables[tmpRenderable.RenderableHash] = tmpRenderable;\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialization */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is initialized.\n\t */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is initialized.\n\t */\n\tonInitialize()\n\t{\n\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Performs view initialization.\n\t */\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\t\t\tthis.onInitialize();\n\t\t\tthis.onAfterInitialize();\n\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Performs view initialization (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initializeAsync:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.info(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} beginning initialization...`);\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t/** @param {Error} pError */\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialization failed: ${pError.message || pError}`, { stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.info(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fCallback();\n\t\t\t\t});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn fCallback();\n\t\t}\n\t}\n\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Render */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is rendered.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that will be rendered.\n\t */\n\tonBeforeRender(pRenderable)\n\t{\n\t\t// Overload this to mess with stuff before the content gets generated from the template\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is rendered (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that will be rendered.\n\t */\n\tonBeforeRenderAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onBeforeRender(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is projected into the DOM.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that will be projected.\n\t */\n\tonBeforeProject(pRenderable)\n\t{\n\t\t// Overload this to mess with stuff before the content gets generated from the template\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeProject:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is projected into the DOM (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that will be projected.\n\t */\n\tonBeforeProjectAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onBeforeProject(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Builds the render options for a renderable.\n\t *\n\t * For DRY purposes on the three flavors of render.\n\t *\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbuildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\tlet tmpRenderOptions = {Valid: true};\n\t\ttmpRenderOptions.RenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t\t\t\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ?\n\t\t\t\t\t\t\t\tthis.options.DefaultRenderable : false;\n\t\tif (!tmpRenderOptions.RenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not find a suitable RenderableHash ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\ttmpRenderOptions.Renderable = this.renderables[tmpRenderOptions.RenderableHash];\n\t\tif (!tmpRenderOptions.Renderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\ttmpRenderOptions.DestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t(typeof (tmpRenderOptions.Renderable.ContentDestinationAddress) === 'string') ? tmpRenderOptions.Renderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : false;\n\t\tif (!tmpRenderOptions.DestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address (param ${pRenderDestinationAddress}).`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRenderOptions.RecordAddress = 'Passed in as object';\n\t\t\ttmpRenderOptions.Record = pTemplateRecordAddress;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderOptions.RecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderOptions.Renderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderOptions.Renderable.DefaultTemplateRecordAddress :\n\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\t\t\ttmpRenderOptions.Record = (typeof (tmpRenderOptions.RecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRenderOptions.RecordAddress) : undefined;\n\t\t}\n\n\t\treturn tmpRenderOptions;\n\t}\n\n\t/**\n\t * Assigns the content to the destination address.\n\t *\n\t * For DRY purposes on the three flavors of render.\n\t *\n\t * @param {Renderable} pRenderable - The renderable to render.\n\t * @param {string} pRenderDestinationAddress - The address where the renderable will be rendered.\n\t * @param {string} pContent - The content to render.\n\t * @returns {boolean} - Returns true if the content was assigned successfully.\n\t * @memberof PictView\n\t */\n\tassignRenderContent(pRenderable, pRenderDestinationAddress, pContent)\n\t{\n\t\treturn this.pict.ContentAssignment.projectContent(pRenderable.RenderMethod, pRenderDestinationAddress, pContent, pRenderable.TestAddress);\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @return {boolean}\n\t */\n\trender(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable)\n\t{\n\t\treturn this.renderWithScope(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable);\n\t}\n\n\t/**\n\t * Render a renderable from this view, providing a specifici scope for the template.\n\t *\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @return {boolean}\n\t */\n\trenderWithScope(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable)\n\t{\n\t\tlet tmpRenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ? this.options.DefaultRenderable : false;\n\t\tif (!tmpRenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it is not a valid renderable.`);\n\t\t\treturn false;\n\t\t}\n\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\t\tif (tmpRenderableHash == '__Virtual')\n\t\t{\n\t\t\ttmpRenderable = {\n\t\t\t\tRenderableHash: '__Virtual',\n\t\t\t\tTemplateHash: this.renderables[this.options.DefaultRenderable].TemplateHash,\n\t\t\t\tContentDestinationAddress: (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null,\n\t\t\t\tRenderMethod: 'virtual-assignment',\n\t\t\t\tTransactionHash: pRootRenderable && pRootRenderable.TransactionHash,\n\t\t\t\tRootRenderableViewHash: pRootRenderable && pRootRenderable.RootRenderableViewHash,\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderable = Object.assign({}, this.renderables[tmpRenderableHash]);\n\t\t\ttmpRenderable.ContentDestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null;\n\t\t}\n\n\t\tif (!tmpRenderable.TransactionHash)\n\t\t{\n\t\t\ttmpRenderable.TransactionHash = `ViewRender-V-${this.options.ViewIdentifier}-R-${tmpRenderableHash}-U-${this.pict.getUUID()}`;\n\t\t\ttmpRenderable.RootRenderableViewHash = this.Hash;\n\t\t\tthis.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);\n\t\t}\n\n\t\tif (!tmpRenderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!tmpRenderable.ContentDestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tlet tmpRecordAddress;\n\t\tlet tmpRecord;\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRecord = pTemplateRecordAddress;\n\t\t\ttmpRecordAddress = 'Passed in as object';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderable.DefaultTemplateRecordAddress :\n\t\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\n\t\t\ttmpRecord = (typeof (tmpRecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRecordAddress) : undefined;\n\t\t}\n\n\t\t// Execute the developer-overridable pre-render behavior\n\t\tthis.onBeforeRender(tmpRenderable);\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] Renderable[${tmpRenderableHash}] Destination[${tmpRenderable.ContentDestinationAddress}] TemplateRecordAddress[${tmpRecordAddress}] render:`);\n\t\t}\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Beginning Render of Renderable[${tmpRenderableHash}] to Destination [${tmpRenderable.ContentDestinationAddress}]...`);\n\t\t}\n\t\t// Generate the content output from the template and data\n\t\ttmpRenderable.Content = this.pict.parseTemplateByHash(tmpRenderable.TemplateHash, tmpRecord, null, [this], pScope, { RootRenderable: typeof pRootRenderable === 'object' ? pRootRenderable : tmpRenderable });\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Assigning Renderable[${tmpRenderableHash}] content length ${tmpRenderable.Content.length} to Destination [${tmpRenderable.ContentDestinationAddress}] using render method [${tmpRenderable.RenderMethod}].`);\n\t\t}\n\n\t\tthis.onBeforeProject(tmpRenderable);\n\t\tthis.onProject(tmpRenderable);\n\n\t\tif (tmpRenderable.RenderMethod !== 'virtual-assignment')\n\t\t{\n\t\t\tthis.onAfterProject(tmpRenderable);\n\n\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\tthis.onAfterRender(tmpRenderable);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t *\n\t * @return {void}\n\t */\n\trenderAsync(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback)\n\t{\n\t\treturn this.renderWithScopeAsync(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback);\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t *\n\t * @return {void}\n\t */\n\trenderWithScopeAsync(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback)\n\t{\n\t\tlet tmpRenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ? this.options.DefaultRenderable : false;\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateRecordAddress) === 'function') ? pTemplateRecordAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\t(typeof(pRootRenderable) === 'function') ? pRootRenderable :\n\t\t\t\t\t\t\tnull;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (!tmpRenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not asynchronously render ${tmpRenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`);\n\t\t\treturn tmpCallback(new Error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not asynchronously render ${tmpRenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`));\n\t\t}\n\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\t\tif (tmpRenderableHash == '__Virtual')\n\t\t{\n\t\t\ttmpRenderable = {\n\t\t\t\tRenderableHash: '__Virtual',\n\t\t\t\tTemplateHash: this.renderables[this.options.DefaultRenderable].TemplateHash,\n\t\t\t\tContentDestinationAddress: (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress : (typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null,\n\t\t\t\tRenderMethod: 'virtual-assignment',\n\t\t\t\tTransactionHash: pRootRenderable && typeof pRootRenderable !== 'function' && pRootRenderable.TransactionHash,\n\t\t\t\tRootRenderableViewHash: pRootRenderable && typeof pRootRenderable !== 'function' && pRootRenderable.RootRenderableViewHash,\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderable = Object.assign({}, this.renderables[tmpRenderableHash]);\n\t\t\ttmpRenderable.ContentDestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null;\n\t\t}\n\n\t\tif (!tmpRenderable.TransactionHash)\n\t\t{\n\t\t\ttmpRenderable.TransactionHash = `ViewRender-V-${this.options.ViewIdentifier}-R-${tmpRenderableHash}-U-${this.pict.getUUID()}`;\n\t\t\ttmpRenderable.RootRenderableViewHash = this.Hash;\n\t\t\tthis.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);\n\t\t}\n\n\t\tif (!tmpRenderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\treturn tmpCallback(new Error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`));\n\t\t}\n\n\t\tif (!tmpRenderable.ContentDestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address.`);\n\t\t\treturn tmpCallback(new Error(`Could not render ${tmpRenderableHash}`));\n\t\t}\n\n\t\tlet tmpRecordAddress;\n\t\tlet tmpRecord;\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRecord = pTemplateRecordAddress;\n\t\t\ttmpRecordAddress = 'Passed in as object';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderable.DefaultTemplateRecordAddress :\n\t\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\n\t\t\ttmpRecord = (typeof (tmpRecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRecordAddress) : undefined;\n\t\t}\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] Renderable[${tmpRenderableHash}] Destination[${tmpRenderable.ContentDestinationAddress}] TemplateRecordAddress[${tmpRecordAddress}] renderAsync:`);\n\t\t}\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Beginning Asynchronous Render (callback-style)...`);\n\t\t}\n\n\t\tlet tmpAnticipate = this.fable.newAnticipate();\n\n\t\ttmpAnticipate.anticipate(\n\t\t\t(fOnBeforeRenderCallback) =>\n\t\t\t{\n\t\t\t\tthis.onBeforeRenderAsync(fOnBeforeRenderCallback, tmpRenderable);\n\t\t\t});\n\n\t\ttmpAnticipate.anticipate(\n\t\t\t(fAsyncTemplateCallback) =>\n\t\t\t{\n\t\t\t\t// Render the template (asynchronously)\n\t\t\t\tthis.pict.parseTemplateByHash(tmpRenderable.TemplateHash, tmpRecord,\n\t\t\t\t\t(pError, pContent) =>\n\t\t\t\t\t{\n\t\t\t\t\t\tif (pError)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render (asynchronously) ${tmpRenderableHash} (param ${pRenderableHash}) because it did not parse the template.`, pError);\n\t\t\t\t\t\t\treturn fAsyncTemplateCallback(pError);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttmpRenderable.Content = pContent;\n\n\t\t\t\t\t\treturn fAsyncTemplateCallback();\n\t\t\t\t\t}, [this], pScope, { RootRenderable: typeof pRootRenderable === 'object' ? pRootRenderable : tmpRenderable });\n\t\t\t});\n\n\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t{\n\t\t\tthis.onBeforeProjectAsync(fNext, tmpRenderable);\n\t\t});\n\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t{\n\t\t\tthis.onProjectAsync(fNext, tmpRenderable);\n\t\t});\n\n\t\tif (tmpRenderable.RenderMethod !== 'virtual-assignment')\n\t\t{\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tthis.onAfterProjectAsync(fNext, tmpRenderable);\n\t\t\t});\n\n\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tthis.onAfterRenderAsync(fNext, tmpRenderable);\n\t\t\t});\n\t\t}\n\n\t\ttmpAnticipate.wait(tmpCallback);\n\t}\n\n\t/**\n\t * Renders the default renderable.\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\trenderDefaultAsync(fCallback)\n\t{\n\t\t// Render the default renderable\n\t\tthis.renderAsync(fCallback);\n\t}\n\n\t/**\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbasicRender(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\treturn this.basicRenderWithScope(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t}\n\n\t/**\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbasicRenderWithScope(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\tlet tmpRenderOptions = this.buildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t\tif (tmpRenderOptions.Valid)\n\t\t{\n\t\t\tthis.assignRenderContent(tmpRenderOptions.Renderable, tmpRenderOptions.DestinationAddress, this.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash, tmpRenderOptions.Record, null, [this], pScope, { RootRenderable: tmpRenderOptions.Renderable }));\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not perform a basic render of ${tmpRenderOptions.RenderableHash} because it is not valid.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t */\n\tbasicRenderAsync(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback)\n\t{\n\t\treturn this.basicRenderWithScopeAsync(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback);\n\t}\n\n\t/**\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t */\n\tbasicRenderWithScopeAsync(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback)\n\t{\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateRecordAddress) === 'function') ? pTemplateRecordAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\tnull;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} basicRenderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} basicRenderAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tconst tmpRenderOptions = this.buildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t\tif (tmpRenderOptions.Valid)\n\t\t{\n\t\t\tthis.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash, tmpRenderOptions.Record,\n\t\t\t\t/**\n\t\t\t\t * @param {Error} [pError] - The error that occurred during template parsing.\n\t\t\t\t * @param {string} [pContent] - The content that was rendered from the template.\n\t\t\t\t */\n\t\t\t\t(pError, pContent) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render (asynchronously) ${tmpRenderOptions.RenderableHash} because it did not parse the template.`, pError);\n\t\t\t\t\t\treturn tmpCallback(pError);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.assignRenderContent(tmpRenderOptions.Renderable, tmpRenderOptions.DestinationAddress, pContent);\n\t\t\t\t\treturn tmpCallback();\n\t\t\t\t}, [this], pScope, { RootRenderable: tmpRenderOptions.Renderable });\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpErrorMessage = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not perform a basic render of ${tmpRenderOptions.RenderableHash} because it is not valid.`;\n\t\t\tthis.log.error(tmpErrorMessage);\n\t\t\treturn tmpCallback(new Error(tmpErrorMessage));\n\t\t}\n\t}\n\n\t/**\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonProject(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onProject:`);\n\t\t}\n\t\tif (pRenderable.RenderMethod === 'virtual-assignment')\n\t\t{\n\t\t\tthis.pict.TransactionTracking.pushToTransactionQueue(pRenderable.TransactionHash, { ViewHash: this.Hash, Renderable: pRenderable }, 'Deferred-Post-Content-Assignment');\n\t\t}\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Assigning Renderable[${pRenderable.RenderableHash}] content length ${pRenderable.Content.length} to Destination [${pRenderable.ContentDestinationAddress}] using Async render method ${pRenderable.RenderMethod}.`);\n\t\t}\n\n\t\t// Assign the content to the destination address\n\t\tthis.pict.ContentAssignment.projectContent(pRenderable.RenderMethod, pRenderable.ContentDestinationAddress, pRenderable.Content, pRenderable.TestAddress);\n\n\t\tthis.lastRenderedTimestamp = this.pict.log.getTimeStamp();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM (async flow).\n\t *\n\t * @param {(error?: Error, content?: string) => void} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that is being projected.\n\t */\n\tonProjectAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onProject(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is rendered.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonAfterRender(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRender:`);\n\t\t}\n\t\tif (pRenderable && pRenderable.RootRenderableViewHash === this.Hash)\n\t\t{\n\t\t\tconst tmpTransactionQueue = this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash) || [];\n\t\t\tfor (const tmpEvent of tmpTransactionQueue)\n\t\t\t{\n\t\t\t\tconst tmpView = this.pict.views[tmpEvent.Data.ViewHash];\n\t\t\t\tif (!tmpView)\n\t\t\t\t{\n\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRender: Could not find view for transaction hash ${pRenderable.TransactionHash} and ViewHash ${tmpEvent.Data.ViewHash}.`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttmpView.onAfterProject();\n\n\t\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\t\ttmpView.onAfterRender(tmpEvent.Data.Renderable);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is rendered (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonAfterRenderAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onAfterRender(pRenderable);\n\t\tconst tmpAnticipate = this.fable.newAnticipate();\n\t\tif (pRenderable && pRenderable.RootRenderableViewHash === this.Hash)\n\t\t{\n\t\t\tconst queue = this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash) || [];\n\t\t\tfor (const event of queue)\n\t\t\t{\n\t\t\t\t/** @type {PictView} */\n\t\t\t\tconst tmpView = this.pict.views[event.Data.ViewHash];\n\t\t\t\tif (!tmpView)\n\t\t\t\t{\n\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRenderAsync: Could not find view for transaction hash ${pRenderable.TransactionHash} and ViewHash ${event.Data.ViewHash}.`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(tmpView.onAfterProjectAsync.bind(tmpView));\n\t\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t\t{\n\t\t\t\t\ttmpView.onAfterRenderAsync(fNext, event.Data.Renderable);\n\t\t\t\t});\n\n\t\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\t}\n\t\t}\n\t\treturn tmpAnticipate.wait(fCallback);\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that was projected.\n\t */\n\tonAfterProject(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterProject:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that was projected.\n\t */\n\tonAfterProjectAsync(fCallback, pRenderable)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Solver */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is solved.\n\t */\n\tonBeforeSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeSolveAsync(fCallback)\n\t{\n\t\tthis.onBeforeSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is solved.\n\t */\n\tonSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonSolveAsync(fCallback)\n\t{\n\t\tthis.onSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Performs view solving and triggers lifecycle hooks.\n\t *\n\t * @return {boolean} - True if the view was solved successfully, false otherwise.\n\t */\n\tsolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeSolve();\n\t\tthis.onSolve();\n\t\tthis.onAfterSolve();\n\t\tthis.lastSolvedTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Performs view solving and triggers lifecycle hooks (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} solveAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSolvedTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is solved.\n\t */\n\tonAfterSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterSolveAsync(fCallback)\n\t{\n\t\tthis.onAfterSolve();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal From View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled from the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tonBeforeMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeMarshalFromViewAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled from the view.\n\t */\n\tonMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonMarshalFromViewAsync(fCallback)\n\t{\n\n\t\tthis.onMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Marshals data from the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tmarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeMarshalFromView();\n\t\tthis.onMarshalFromView();\n\t\tthis.onAfterMarshalFromView();\n\t\tthis.lastMarshalFromViewTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Marshals data from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tmarshalFromViewAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalFromViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onMarshalFromViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalFromViewAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} marshalFromViewAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalFromViewTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled from the view.\n\t */\n\tonAfterMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterMarshalFromViewAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal To View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled into the view.\n\t */\n\tonBeforeMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled into the view.\n\t */\n\tonMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Marshals data into the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tmarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeMarshalToView();\n\t\tthis.onMarshalToView();\n\t\tthis.onAfterMarshalToView();\n\t\tthis.lastMarshalToViewTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Marshals data into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tmarshalToViewAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalToViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onMarshalToViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalToViewAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} marshalToViewAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalToViewTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled into the view.\n\t */\n\tonAfterMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/** @return {boolean} - True if the object is a PictView. */\n\tget isPictView()\n\t{\n\t\treturn true;\n\t}\n}\n\nmodule.exports = PictView;\n\n},{\"../package.json\":12,\"fable-serviceproviderbase\":2}],14:[function(require,module,exports){\n// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n\n},{}],15:[function(require,module,exports){\nmodule.exports={\n\t\"Name\": \"Retold Data Cloner\",\n\t\"Hash\": \"DataCloner\",\n\t\"MainViewportViewIdentifier\": \"DataCloner-Layout\",\n\t\"MainViewportDestinationAddress\": \"#DataCloner-Application-Container\",\n\t\"MainViewportDefaultDataAddress\": \"AppData.DataCloner\",\n\t\"pict_configuration\": { \"Product\": \"DataCloner\" },\n\t\"AutoRenderMainViewportViewAfterInitialize\": false\n}\n\n},{}],16:[function(require,module,exports){\nconst libPictApplication = require('pict-application');\n\nconst libProvider = require('./providers/Pict-Provider-DataCloner.js');\n\nconst libViewLayout = require('./views/PictView-DataCloner-Layout.js');\nconst libViewConnection = require('./views/PictView-DataCloner-Connection.js');\nconst libViewSession = require('./views/PictView-DataCloner-Session.js');\nconst libViewSchema = require('./views/PictView-DataCloner-Schema.js');\nconst libViewDeploy = require('./views/PictView-DataCloner-Deploy.js');\nconst libViewSync = require('./views/PictView-DataCloner-Sync.js');\nconst libViewExport = require('./views/PictView-DataCloner-Export.js');\nconst libViewViewData = require('./views/PictView-DataCloner-ViewData.js');\nconst libViewHistogram = require('pict-section-histogram');\n\nclass DataClonerApplication extends libPictApplication\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\n\t\t// Register provider\n\t\tthis.pict.addProvider('DataCloner', libProvider.default_configuration, libProvider);\n\n\t\t// Register views\n\t\tthis.pict.addView('DataCloner-Layout', libViewLayout.default_configuration, libViewLayout);\n\t\tthis.pict.addView('DataCloner-Connection', libViewConnection.default_configuration, libViewConnection);\n\t\tthis.pict.addView('DataCloner-Session', libViewSession.default_configuration, libViewSession);\n\t\tthis.pict.addView('DataCloner-Schema', libViewSchema.default_configuration, libViewSchema);\n\t\tthis.pict.addView('DataCloner-Deploy', libViewDeploy.default_configuration, libViewDeploy);\n\t\tthis.pict.addView('DataCloner-Sync', libViewSync.default_configuration, libViewSync);\n\t\tthis.pict.addView('DataCloner-Export', libViewExport.default_configuration, libViewExport);\n\t\tthis.pict.addView('DataCloner-ViewData', libViewViewData.default_configuration, libViewViewData);\n\t\tthis.pict.addView('DataCloner-StatusHistogram',\n\t\t\t{\n\t\t\t\tViewIdentifier: 'DataCloner-StatusHistogram',\n\t\t\t\tTargetElementAddress: '#DataCloner-Throughput-Histogram',\n\t\t\t\tDefaultDestinationAddress: '#DataCloner-Throughput-Histogram',\n\t\t\t\tRenderOnLoad: false,\n\t\t\t\tSelectable: false,\n\t\t\t\tOrientation: 'vertical',\n\t\t\t\tFillContainer: true,\n\t\t\t\tShowValues: false,\n\t\t\t\tShowLabels: true,\n\t\t\t\tMaxBarSize: 80,\n\t\t\t\tBarColor: '#4a90d9',\n\t\t\t\tBins: []\n\t\t\t}, libViewHistogram);\n\t}\n\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\t// Centralized state (replaces global variables)\n\t\tthis.pict.AppData.DataCloner =\n\t\t{\n\t\t\tFetchedTables: [],\n\t\t\tDeployedTables: [],\n\t\t\tLastReport: null,\n\t\t\tServerBusyAtLoad: false,\n\t\t\tSyncPollTimer: null,\n\t\t\tLiveStatusTimer: null,\n\t\t\tStatusDetailExpanded: false,\n\t\t\tStatusDetailAutoExpanded: false,\n\t\t\tStatusDetailTimer: null,\n\t\t\tStatusDetailData: null,\n\t\t\tLastLiveStatus: null,\n\t\t\tPersistFields: [\n\t\t\t\t'serverURL', 'authMethod', 'authURI', 'checkURI',\n\t\t\t\t'cookieName', 'cookieValueAddr', 'cookieValueTemplate', 'loginMarker',\n\t\t\t\t'userName', 'password', 'schemaURL', 'pageSize', 'dateTimePrecisionMS',\n\t\t\t\t'connProvider', 'sqliteFilePath',\n\t\t\t\t'mysqlServer', 'mysqlPort', 'mysqlUser', 'mysqlPassword', 'mysqlDatabase', 'mysqlConnectionLimit',\n\t\t\t\t'mssqlServer', 'mssqlPort', 'mssqlUser', 'mssqlPassword', 'mssqlDatabase', 'mssqlConnectionLimit',\n\t\t\t\t'postgresqlHost', 'postgresqlPort', 'postgresqlUser', 'postgresqlPassword', 'postgresqlDatabase', 'postgresqlConnectionLimit',\n\t\t\t\t'solrHost', 'solrPort', 'solrCore', 'solrPath',\n\t\t\t\t'mongodbHost', 'mongodbPort', 'mongodbUser', 'mongodbPassword', 'mongodbDatabase', 'mongodbConnectionLimit',\n\t\t\t\t'rocksdbFolder',\n\t\t\t\t'bibliographFolder',\n\t\t\t\t'syncMaxRecords'\n\t\t\t]\n\t\t};\n\n\t\t// Make pict available for inline onclick handlers\n\t\twindow.pict = this.pict;\n\n\t\t// Render layout (which chains child view renders via onAfterRender)\n\t\tthis.pict.views['DataCloner-Layout'].render();\n\n\t\t// Post-render initialization\n\t\tthis.pict.providers.DataCloner.initPersistence();\n\t\tthis.pict.views['DataCloner-Connection'].onProviderChange();\n\t\tthis.pict.providers.DataCloner.restoreDeployedTables();\n\t\tthis.pict.providers.DataCloner.startLiveStatusPolling();\n\t\tthis.pict.providers.DataCloner.initAccordionPreviews();\n\t\tthis.pict.providers.DataCloner.updateAllPreviews();\n\t\tthis.pict.views['DataCloner-Layout'].collapseAllSections();\n\t\tthis.pict.providers.DataCloner.initAutoProcess();\n\n\t\treturn fCallback();\n\t}\n}\n\nmodule.exports = DataClonerApplication;\n\nmodule.exports.default_configuration = require('./Pict-Application-DataCloner-Configuration.json');\n\n},{\"./Pict-Application-DataCloner-Configuration.json\":15,\"./providers/Pict-Provider-DataCloner.js\":18,\"./views/PictView-DataCloner-Connection.js\":19,\"./views/PictView-DataCloner-Deploy.js\":20,\"./views/PictView-DataCloner-Export.js\":21,\"./views/PictView-DataCloner-Layout.js\":22,\"./views/PictView-DataCloner-Schema.js\":23,\"./views/PictView-DataCloner-Session.js\":24,\"./views/PictView-DataCloner-Sync.js\":25,\"./views/PictView-DataCloner-ViewData.js\":26,\"pict-application\":4,\"pict-section-histogram\":8}],17:[function(require,module,exports){\nmodule.exports = { DataClonerApplication: require('./Pict-Application-DataCloner.js') };\n\nif (typeof(window) !== 'undefined')\n{\n\twindow.DataClonerApplication = module.exports.DataClonerApplication;\n}\n\n},{\"./Pict-Application-DataCloner.js\":16}],18:[function(require,module,exports){\nconst libPictProvider = require('pict-provider');\n\nclass DataClonerProvider extends libPictProvider\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\t// ================================================================\n\t// API Helper\n\t// ================================================================\n\n\tapi(pMethod, pPath, pBody)\n\t{\n\t\tlet tmpOpts = { method: pMethod, headers: {} };\n\t\tif (pBody)\n\t\t{\n\t\t\ttmpOpts.headers['Content-Type'] = 'application/json';\n\t\t\ttmpOpts.body = JSON.stringify(pBody);\n\t\t}\n\t\treturn fetch(pPath, tmpOpts).then(function(pResponse) { return pResponse.json(); });\n\t}\n\n\tsetStatus(pElementId, pMessage, pType)\n\t{\n\t\tlet tmpEl = document.getElementById(pElementId);\n\t\tif (!tmpEl) return;\n\t\ttmpEl.className = 'status ' + (pType || 'info');\n\t\ttmpEl.textContent = pMessage;\n\t\ttmpEl.style.display = 'block';\n\t}\n\n\tescapeHtml(pStr)\n\t{\n\t\tlet tmpDiv = document.createElement('div');\n\t\ttmpDiv.appendChild(document.createTextNode(pStr));\n\t\treturn tmpDiv.innerHTML;\n\t}\n\n\t// ================================================================\n\t// Phase status indicators\n\t// ================================================================\n\n\tsetSectionPhase(pSection, pState)\n\t{\n\t\tlet tmpEl = document.getElementById('phase' + pSection);\n\t\tif (!tmpEl) return;\n\n\t\ttmpEl.className = 'accordion-phase';\n\n\t\tif (pState === 'ok')\n\t\t{\n\t\t\ttmpEl.innerHTML = '✓';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-ok');\n\t\t}\n\t\telse if (pState === 'error')\n\t\t{\n\t\t\ttmpEl.innerHTML = '✗';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-error');\n\t\t}\n\t\telse if (pState === 'busy')\n\t\t{\n\t\t\ttmpEl.innerHTML = '<span class=\"phase-spinner\"></span>';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-busy');\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpEl.innerHTML = '';\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Accordion Previews\n\t// ================================================================\n\n\tupdateAllPreviews()\n\t{\n\t\t// Section 1 — Database Connection\n\t\tlet tmpProvider = document.getElementById('connProvider');\n\t\tif (!tmpProvider) return;\n\t\ttmpProvider = tmpProvider.value;\n\t\tlet tmpPreview1 = tmpProvider;\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\tlet tmpPath = document.getElementById('sqliteFilePath').value || '~/headlight-liveconnect-local/cloned.sqlite';\n\t\t\ttmpPreview1 = 'SQLite at ' + tmpPath;\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mysqlServer').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mysqlPort').value || '3306';\n\t\t\tlet tmpUser = document.getElementById('mysqlUser').value || 'root';\n\t\t\ttmpPreview1 = 'MySQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mssqlServer').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mssqlPort').value || '1433';\n\t\t\tlet tmpUser = document.getElementById('mssqlUser').value || 'sa';\n\t\t\ttmpPreview1 = 'MSSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('postgresqlHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('postgresqlPort').value || '5432';\n\t\t\tlet tmpUser = document.getElementById('postgresqlUser').value || 'postgres';\n\t\t\ttmpPreview1 = 'PostgreSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'MongoDB')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mongodbHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mongodbPort').value || '27017';\n\t\t\ttmpPreview1 = 'MongoDB on ' + tmpHost + ':' + tmpPort;\n\t\t}\n\t\telse if (tmpProvider === 'Solr')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('solrHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('solrPort').value || '8983';\n\t\t\ttmpPreview1 = 'Solr on ' + tmpHost + ':' + tmpPort;\n\t\t}\n\t\telse if (tmpProvider === 'RocksDB')\n\t\t{\n\t\t\tlet tmpFolder = document.getElementById('rocksdbFolder').value || '~/headlight-liveconnect-local/rocksdb';\n\t\t\ttmpPreview1 = 'RocksDB at ' + tmpFolder;\n\t\t}\n\t\telse if (tmpProvider === 'Bibliograph')\n\t\t{\n\t\t\tlet tmpFolder = document.getElementById('bibliographFolder').value || '~/headlight-liveconnect-local/bibliograph';\n\t\t\ttmpPreview1 = 'Bibliograph at ' + tmpFolder;\n\t\t}\n\t\tdocument.getElementById('preview1').textContent = tmpPreview1;\n\n\t\t// Section 2 — Remote Session\n\t\tlet tmpServerURL = document.getElementById('serverURL').value;\n\t\tlet tmpUserName = document.getElementById('userName').value;\n\t\tif (tmpServerURL)\n\t\t{\n\t\t\tlet tmpPreview2 = tmpServerURL;\n\t\t\tif (tmpUserName) tmpPreview2 += ' as ' + tmpUserName;\n\t\t\tdocument.getElementById('preview2').textContent = tmpPreview2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview2').textContent = 'Configure remote server URL and credentials';\n\t\t}\n\n\t\t// Section 3 — Remote Schema\n\t\tlet tmpTableChecks = document.querySelectorAll('#tableList input[type=\"checkbox\"]:checked');\n\t\tif (tmpTableChecks.length > 0)\n\t\t{\n\t\t\tdocument.getElementById('preview3').textContent = tmpTableChecks.length + ' table' + (tmpTableChecks.length === 1 ? '' : 's') + ' selected';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value;\n\t\t\tif (tmpSchemaURL)\n\t\t\t{\n\t\t\t\tdocument.getElementById('preview3').textContent = 'Schema from ' + tmpSchemaURL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById('preview3').textContent = 'Fetch and select tables from the remote server';\n\t\t\t}\n\t\t}\n\n\t\t// Section 4 — Deploy Schema\n\t\tlet tmpDeployedEl = document.getElementById('deployStatus');\n\t\tlet tmpDeployedText = tmpDeployedEl ? tmpDeployedEl.textContent : '';\n\t\tif (tmpDeployedText && tmpDeployedText.indexOf('deployed') !== -1)\n\t\t{\n\t\t\tdocument.getElementById('preview4').textContent = tmpDeployedText;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview4').textContent = 'Create selected tables in the local database';\n\t\t}\n\n\t\t// Section 5 — Synchronize Data\n\t\tlet tmpSyncMode = document.querySelector('input[name=\"syncMode\"]:checked');\n\t\tlet tmpModeName = tmpSyncMode ? tmpSyncMode.value : 'Initial';\n\t\tlet tmpPageSize = document.getElementById('pageSize').value || '100';\n\t\tlet tmpSyncPreview = tmpModeName + ' sync, page size ' + tmpPageSize;\n\t\tlet tmpDeleted = document.getElementById('syncDeletedRecords').checked;\n\t\tif (tmpDeleted) tmpSyncPreview += ', including deleted';\n\t\tdocument.getElementById('preview5').textContent = tmpSyncPreview;\n\n\t\t// Section 6 — Export Configuration\n\t\tlet tmpMaxRecords = document.getElementById('syncMaxRecords').value;\n\t\tlet tmpLogFile = document.getElementById('syncLogFile').checked;\n\t\tlet tmpExportParts = [];\n\t\tif (tmpMaxRecords && parseInt(tmpMaxRecords, 10) > 0) tmpExportParts.push('max ' + tmpMaxRecords + ' records');\n\t\tif (tmpLogFile) tmpExportParts.push('log enabled');\n\t\telse tmpExportParts.push('log disabled');\n\t\tdocument.getElementById('preview6').textContent = tmpExportParts.length > 0 ? 'Export: ' + tmpExportParts.join(', ') : 'Generate JSON config for headless cloning';\n\n\t\t// Section 7 — View Data\n\t\tlet tmpViewTable = document.getElementById('viewTable').value;\n\t\tif (tmpViewTable)\n\t\t{\n\t\t\tdocument.getElementById('preview7').textContent = 'Viewing ' + tmpViewTable;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview7').textContent = 'Browse synced table data';\n\t\t}\n\t}\n\n\tinitAccordionPreviews()\n\t{\n\t\tlet tmpSelf = this;\n\n\t\tlet tmpPreviewFields = [\n\t\t\t'connProvider', 'sqliteFilePath',\n\t\t\t'mysqlServer', 'mysqlPort', 'mysqlUser',\n\t\t\t'mssqlServer', 'mssqlPort', 'mssqlUser',\n\t\t\t'postgresqlHost', 'postgresqlPort', 'postgresqlUser',\n\t\t\t'mongodbHost', 'mongodbPort',\n\t\t\t'solrHost', 'solrPort',\n\t\t\t'rocksdbFolder', 'bibliographFolder',\n\t\t\t'serverURL', 'userName',\n\t\t\t'schemaURL',\n\t\t\t'pageSize', 'dateTimePrecisionMS',\n\t\t\t'syncMaxRecords',\n\t\t\t'viewTable', 'viewLimit'\n\t\t];\n\n\t\tlet tmpHandler = function() { tmpSelf.updateAllPreviews(); };\n\n\t\tfor (let i = 0; i < tmpPreviewFields.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById(tmpPreviewFields[i]);\n\t\t\tif (tmpEl)\n\t\t\t{\n\t\t\t\ttmpEl.addEventListener('input', tmpHandler);\n\t\t\t\ttmpEl.addEventListener('change', tmpHandler);\n\t\t\t}\n\t\t}\n\n\t\t// Checkboxes and radios\n\t\tlet tmpCheckboxes = ['syncDeletedRecords', 'syncLogFile'];\n\t\tfor (let i = 0; i < tmpCheckboxes.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById(tmpCheckboxes[i]);\n\t\t\tif (tmpEl) tmpEl.addEventListener('change', tmpHandler);\n\t\t}\n\n\t\tdocument.querySelectorAll('input[name=\"syncMode\"]').forEach(function(pEl)\n\t\t{\n\t\t\tpEl.addEventListener('change', tmpHandler);\n\t\t});\n\t}\n\n\t// ================================================================\n\t// LocalStorage Persistence\n\t// ================================================================\n\n\tsaveField(pFieldId)\n\t{\n\t\tlet tmpEl = document.getElementById(pFieldId);\n\t\tif (tmpEl)\n\t\t{\n\t\t\tlocalStorage.setItem('dataCloner_' + pFieldId, tmpEl.value);\n\t\t}\n\t}\n\n\trestoreFields()\n\t{\n\t\tlet tmpPersistFields = this.pict.AppData.DataCloner.PersistFields;\n\t\tfor (let i = 0; i < tmpPersistFields.length; i++)\n\t\t{\n\t\t\tlet tmpId = tmpPersistFields[i];\n\t\t\tlet tmpSaved = localStorage.getItem('dataCloner_' + tmpId);\n\t\t\tif (tmpSaved !== null)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(tmpId);\n\t\t\t\tif (tmpEl) tmpEl.value = tmpSaved;\n\t\t\t}\n\t\t}\n\n\t\t// Restore checkbox state\n\t\tlet tmpSyncDeleted = localStorage.getItem('dataCloner_syncDeletedRecords');\n\t\tif (tmpSyncDeleted !== null)\n\t\t{\n\t\t\tdocument.getElementById('syncDeletedRecords').checked = tmpSyncDeleted === 'true';\n\t\t}\n\t\t// Restore sync mode\n\t\tlet tmpSyncMode = localStorage.getItem('dataCloner_syncMode');\n\t\tif (tmpSyncMode === 'Ongoing')\n\t\t{\n\t\t\tdocument.getElementById('syncModeOngoing').checked = true;\n\t\t}\n\t\tlet tmpSolrSecure = localStorage.getItem('dataCloner_solrSecure');\n\t\tif (tmpSolrSecure !== null)\n\t\t{\n\t\t\tdocument.getElementById('solrSecure').checked = tmpSolrSecure === 'true';\n\t\t}\n\t\t// Restore advanced ID pagination checkbox\n\t\tlet tmpAdvancedIDPagination = localStorage.getItem('dataCloner_syncAdvancedIDPagination');\n\t\tif (tmpAdvancedIDPagination !== null)\n\t\t{\n\t\t\tdocument.getElementById('syncAdvancedIDPagination').checked = tmpAdvancedIDPagination === 'true';\n\t\t}\n\t}\n\n\tinitPersistence()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.restoreFields();\n\n\t\tlet tmpPersistFields = this.pict.AppData.DataCloner.PersistFields;\n\t\tfor (let i = 0; i < tmpPersistFields.length; i++)\n\t\t{\n\t\t\t(function(pId)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(pId);\n\t\t\t\tif (tmpEl)\n\t\t\t\t{\n\t\t\t\t\ttmpEl.addEventListener('input', function() { tmpSelf.saveField(pId); });\n\t\t\t\t\ttmpEl.addEventListener('change', function() { tmpSelf.saveField(pId); });\n\t\t\t\t}\n\t\t\t})(tmpPersistFields[i]);\n\t\t}\n\n\t\t// Persist sync deleted checkbox\n\t\tlet tmpSyncDeletedEl = document.getElementById('syncDeletedRecords');\n\t\tif (tmpSyncDeletedEl)\n\t\t{\n\t\t\ttmpSyncDeletedEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncDeletedRecords', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist sync mode radio\n\t\tdocument.querySelectorAll('input[name=\"syncMode\"]').forEach(function(pEl)\n\t\t{\n\t\t\tpEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncMode', this.value);\n\t\t\t});\n\t\t});\n\n\t\t// Persist solr secure checkbox\n\t\tlet tmpSolrSecureEl = document.getElementById('solrSecure');\n\t\tif (tmpSolrSecureEl)\n\t\t{\n\t\t\ttmpSolrSecureEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_solrSecure', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist advanced ID pagination checkbox\n\t\tlet tmpAdvancedIDPaginationEl = document.getElementById('syncAdvancedIDPagination');\n\t\tif (tmpAdvancedIDPaginationEl)\n\t\t{\n\t\t\ttmpAdvancedIDPaginationEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncAdvancedIDPagination', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist auto-process checkboxes\n\t\tlet tmpAutoIds = ['auto1', 'auto2', 'auto3', 'auto4', 'auto5'];\n\t\tfor (let a = 0; a < tmpAutoIds.length; a++)\n\t\t{\n\t\t\t(function(pId)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(pId);\n\t\t\t\tif (tmpEl)\n\t\t\t\t{\n\t\t\t\t\tlet tmpSaved = localStorage.getItem('dataCloner_' + pId);\n\t\t\t\t\tif (tmpSaved !== null) tmpEl.checked = tmpSaved === 'true';\n\t\t\t\t\ttmpEl.addEventListener('change', function()\n\t\t\t\t\t{\n\t\t\t\t\t\tlocalStorage.setItem('dataCloner_' + pId, this.checked);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})(tmpAutoIds[a]);\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Live Status Indicator\n\t// ================================================================\n\n\tstartLiveStatusPolling()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\tif (tmpAppData.LiveStatusTimer) clearInterval(tmpAppData.LiveStatusTimer);\n\t\tthis.pollLiveStatus();\n\t\tlet tmpSelf = this;\n\t\ttmpAppData.LiveStatusTimer = setInterval(function() { tmpSelf.pollLiveStatus(); }, 1500);\n\t}\n\n\tpollLiveStatus()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/live-status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.renderLiveStatus(pData);\n\t\t\t})\n\t\t\t.catch(function()\n\t\t\t{\n\t\t\t\ttmpSelf.renderLiveStatus({ Phase: 'disconnected', Message: 'Cannot reach server', TotalSynced: 0, TotalRecords: 0 });\n\t\t\t});\n\t}\n\n\trenderLiveStatus(pData)\n\t{\n\t\t// Cache the live status data for the detail view\n\t\tthis.pict.AppData.DataCloner.LastLiveStatus = pData;\n\n\t\tlet tmpBar = document.getElementById('liveStatusBar');\n\t\tlet tmpMsg = document.getElementById('liveStatusMessage');\n\t\tlet tmpMeta = document.getElementById('liveStatusMeta');\n\t\tlet tmpProgressFill = document.getElementById('liveStatusProgressFill');\n\t\tif (!tmpBar) return;\n\n\t\t// Update phase class (preserve expanded class if present)\n\t\tlet tmpWasExpanded = tmpBar.classList.contains('expanded');\n\t\ttmpBar.className = 'live-status-bar phase-' + (pData.Phase || 'idle');\n\t\tif (tmpWasExpanded) tmpBar.classList.add('expanded');\n\n\t\t// Update message\n\t\ttmpMsg.textContent = pData.Message || 'Idle';\n\n\t\t// Update meta info\n\t\tlet tmpMetaParts = [];\n\t\tif (pData.Phase === 'syncing' || pData.Phase === 'stopping')\n\t\t{\n\t\t\tif (pData.Elapsed)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + pData.Elapsed + '</span>');\n\t\t\t}\n\t\t\tif (pData.ETA)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">~' + pData.ETA + ' remaining</span>');\n\t\t\t}\n\t\t\tif (pData.TotalTables > 0)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + pData.Completed + '</strong> / ' + pData.TotalTables + ' tables</span>');\n\t\t\t}\n\t\t\tif (pData.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = pData.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\tif (pData.PreCountGrandTotal > 0)\n\t\t\t\t{\n\t\t\t\t\tlet tmpGrandTotal = pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> / ' + tmpGrandTotal + ' records</span>');\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (pData.PreCountGrandTotal > 0)\n\t\t\t{\n\t\t\t\tlet tmpGrandTotal = pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">' + tmpGrandTotal + ' records to sync</span>');\n\t\t\t}\n\t\t\tif (pData.PreCountProgress && pData.PreCountProgress.Counted < pData.PreCountProgress.TotalTables)\n\t\t\t{\n\t\t\t\tlet tmpCountedSoFar = pData.PreCountGrandTotal > 0\n\t\t\t\t\t? ' (' + pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + ' records found)'\n\t\t\t\t\t: '';\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">counting: ' + pData.PreCountProgress.Counted + ' / ' + pData.PreCountProgress.TotalTables + ' tables' + tmpCountedSoFar + '</span>');\n\t\t\t}\n\t\t\tif (pData.Errors > 0)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\" style=\"color:#dc3545\"><strong>' + pData.Errors + '</strong> error' + (pData.Errors === 1 ? '' : 's') + '</span>');\n\t\t\t}\n\t\t}\n\t\telse if (pData.Phase === 'complete')\n\t\t{\n\t\t\tif (pData.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = pData.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records synced</span>');\n\t\t\t}\n\t\t}\n\t\ttmpMeta.innerHTML = tmpMetaParts.join('');\n\n\t\t// Update progress bar\n\t\tlet tmpPct = 0;\n\t\tif (pData.Phase === 'syncing' && pData.PreCountProgress && pData.PreCountProgress.Counted < pData.PreCountProgress.TotalTables)\n\t\t{\n\t\t\t// During counting phase, show table counting progress\n\t\t\ttmpPct = Math.min((pData.PreCountProgress.Counted / pData.PreCountProgress.TotalTables) * 100, 99);\n\t\t}\n\t\telse if (pData.Phase === 'syncing' && pData.PreCountGrandTotal > 0 && pData.TotalSynced > 0)\n\t\t{\n\t\t\ttmpPct = Math.min((pData.TotalSynced / pData.PreCountGrandTotal) * 100, 99.9);\n\t\t}\n\t\telse if (pData.Phase === 'syncing' && pData.TotalTables > 0)\n\t\t{\n\t\t\tlet tmpTablePct = (pData.Completed / pData.TotalTables) * 100;\n\t\t\tif (pData.ActiveProgress && pData.ActiveProgress.Total > 0)\n\t\t\t{\n\t\t\t\tlet tmpEntityPct = (pData.ActiveProgress.Synced / pData.ActiveProgress.Total) * (100 / pData.TotalTables);\n\t\t\t\ttmpPct = tmpTablePct + tmpEntityPct;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpPct = tmpTablePct;\n\t\t\t}\n\t\t}\n\t\telse if (pData.Phase === 'complete')\n\t\t{\n\t\t\ttmpPct = 100;\n\t\t}\n\t\ttmpProgressFill.style.width = Math.min(100, Math.round(tmpPct)) + '%';\n\n\t\t// Auto-expand the detail view once when sync first starts so users see counting progress.\n\t\t// Only expand once per sync run — if the user collapses it, respect that choice.\n\t\tif ((pData.Phase === 'syncing' || pData.Phase === 'stopping') && !this.pict.AppData.DataCloner.StatusDetailExpanded && !this.pict.AppData.DataCloner.StatusDetailAutoExpanded)\n\t\t{\n\t\t\tthis.pict.AppData.DataCloner.StatusDetailAutoExpanded = true;\n\t\t\tlet tmpLayoutView = this.pict.views['DataCloner-Layout'];\n\t\t\tif (tmpLayoutView && typeof tmpLayoutView.toggleStatusDetail === 'function')\n\t\t\t{\n\t\t\t\ttmpLayoutView.toggleStatusDetail();\n\t\t\t}\n\t\t}\n\n\t\t// Reset the auto-expand flag when the sync is no longer running,\n\t\t// so the next sync run will auto-expand again.\n\t\tif (pData.Phase !== 'syncing' && pData.Phase !== 'stopping')\n\t\t{\n\t\t\tthis.pict.AppData.DataCloner.StatusDetailAutoExpanded = false;\n\t\t}\n\n\t\t// If the detail view is expanded, re-render it with fresh data\n\t\tif (this.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t{\n\t\t\tthis.renderStatusDetail();\n\t\t}\n\n\t\t// Auto-fetch the sync report when we detect a completed sync but haven't loaded the report yet\n\t\tif (pData.Phase === 'complete' && !this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tlet tmpSelf = this;\n\t\t\tthis.api('GET', '/clone/sync/report')\n\t\t\t\t.then(function(pReportData)\n\t\t\t\t{\n\t\t\t\t\tif (pReportData && pReportData.ReportVersion)\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.LastReport = pReportData;\n\t\t\t\t\t\tif (tmpSelf.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.renderStatusDetail();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch(function() { /* ignore fetch errors */ });\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Status Detail Expansion\n\t// ================================================================\n\n\tonStatusDetailExpanded()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\ttmpAppData.StatusDetailExpanded = true;\n\n\t\t// Immediate render from whatever data we have\n\t\tthis.renderStatusDetail();\n\n\t\t// Start detail polling (poll /sync/status for per-table data)\n\t\tif (tmpAppData.StatusDetailTimer) clearInterval(tmpAppData.StatusDetailTimer);\n\t\tlet tmpSelf = this;\n\t\ttmpAppData.StatusDetailTimer = setInterval(function() { tmpSelf.pollStatusDetail(); }, 2000);\n\t\tthis.pollStatusDetail();\n\t}\n\n\tonStatusDetailCollapsed()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\ttmpAppData.StatusDetailExpanded = false;\n\n\t\tif (tmpAppData.StatusDetailTimer)\n\t\t{\n\t\t\tclearInterval(tmpAppData.StatusDetailTimer);\n\t\t\ttmpAppData.StatusDetailTimer = null;\n\t\t}\n\t}\n\n\tpollStatusDetail()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.AppData.DataCloner.StatusDetailData = pData;\n\t\t\t\ttmpSelf.renderStatusDetail();\n\t\t\t})\n\t\t\t.catch(function() { /* ignore poll errors */ });\n\t}\n\n\trenderCountingPhaseDetail(pContainer, pPreCountProgress)\n\t{\n\t\tlet tmpTables = pPreCountProgress.Tables || [];\n\t\tlet tmpCounted = pPreCountProgress.Counted || 0;\n\t\tlet tmpTotal = pPreCountProgress.TotalTables || 0;\n\t\tlet tmpRunningTotal = 0;\n\n\t\tlet tmpHtml = '<div class=\"status-detail-section\">';\n\t\ttmpHtml += '<div class=\"status-detail-section-title\">Counting Records (' + tmpCounted + ' / ' + tmpTotal + ' tables)</div>';\n\n\t\tif (tmpTables.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<table class=\"precount-table\">';\n\t\t\ttmpHtml += '<thead><tr><th>Table</th><th style=\"text-align:right\">Records</th><th style=\"text-align:right\">Time</th></tr></thead>';\n\t\t\ttmpHtml += '<tbody>';\n\t\t\tfor (let i = 0; i < tmpTables.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpT = tmpTables[i];\n\t\t\t\ttmpRunningTotal += tmpT.Count;\n\t\t\t\tlet tmpCountFmt = this.formatNumber(tmpT.Count);\n\t\t\t\tlet tmpTimeFmt = tmpT.ElapsedMs < 1000\n\t\t\t\t\t? tmpT.ElapsedMs + 'ms'\n\t\t\t\t\t: (tmpT.ElapsedMs / 1000).toFixed(1) + 's';\n\t\t\t\tlet tmpRowClass = tmpT.Error ? ' class=\"precount-error\"' : '';\n\t\t\t\ttmpHtml += '<tr' + tmpRowClass + '>';\n\t\t\t\ttmpHtml += '<td>' + this.escapeHtml(tmpT.Name) + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums\">' + tmpCountFmt + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums; color:#888\">' + tmpTimeFmt + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</tbody>';\n\t\t\ttmpHtml += '<tfoot><tr>';\n\t\t\ttmpHtml += '<td><strong>Total</strong></td>';\n\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums\"><strong>' + this.formatNumber(tmpRunningTotal) + '</strong></td>';\n\t\t\ttmpHtml += '<td></td>';\n\t\t\ttmpHtml += '</tr></tfoot>';\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// Show pending indicator for remaining tables\n\t\tlet tmpRemaining = tmpTotal - tmpCounted;\n\t\tif (tmpRemaining > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"precount-pending\">';\n\t\t\ttmpHtml += '<span class=\"precount-spinner\"></span> ';\n\t\t\ttmpHtml += tmpRemaining + ' table' + (tmpRemaining === 1 ? '' : 's') + ' remaining…';\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\tpContainer.innerHTML = tmpHtml;\n\t}\n\n\trenderStatusDetail()\n\t{\n\t\tlet tmpContainer = document.getElementById('DataCloner-StatusDetail-Container');\n\t\tif (!tmpContainer) return;\n\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\tlet tmpLiveStatus = tmpAppData.LastLiveStatus;\n\t\tlet tmpStatusData = tmpAppData.StatusDetailData;\n\t\tlet tmpReport = tmpAppData.LastReport;\n\n\t\t// During the counting phase, show per-table counts as they arrive\n\t\tif (tmpLiveStatus && tmpLiveStatus.PreCountProgress\n\t\t\t&& tmpLiveStatus.PreCountProgress.Tables\n\t\t\t&& tmpLiveStatus.Phase === 'syncing'\n\t\t\t&& tmpLiveStatus.PreCountProgress.Counted < tmpLiveStatus.PreCountProgress.TotalTables)\n\t\t{\n\t\t\tthis.renderCountingPhaseDetail(tmpContainer, tmpLiveStatus.PreCountProgress);\n\t\t\t// Prepend the summary banner above the counting detail\n\t\t\tlet tmpSummaryBanner = this.buildStatusSummaryHtml();\n\t\t\tif (tmpSummaryBanner)\n\t\t\t{\n\t\t\t\ttmpContainer.innerHTML = tmpSummaryBanner + tmpContainer.innerHTML;\n\t\t\t}\n\t\t\t// Hide histogram during counting\n\t\t\tlet tmpHistContainer = document.getElementById('DataCloner-Throughput-Histogram');\n\t\t\tif (tmpHistContainer) tmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine data source: live during sync, report after sync\n\t\tlet tmpTables = {};\n\t\tlet tmpThroughputSamples = [];\n\t\tlet tmpEventLog = [];\n\t\tlet tmpIsLive = false;\n\n\t\tif (tmpLiveStatus && (tmpLiveStatus.Phase === 'syncing' || tmpLiveStatus.Phase === 'stopping'))\n\t\t{\n\t\t\ttmpIsLive = true;\n\t\t\tif (tmpStatusData && tmpStatusData.Tables) tmpTables = tmpStatusData.Tables;\n\t\t\tif (tmpLiveStatus.ThroughputSamples) tmpThroughputSamples = tmpLiveStatus.ThroughputSamples;\n\t\t}\n\t\telse if (tmpReport && tmpReport.ReportVersion)\n\t\t{\n\t\t\t// Build tables object from report\n\t\t\tfor (let i = 0; i < tmpReport.Tables.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpT = tmpReport.Tables[i];\n\t\t\t\ttmpTables[tmpT.Name] = tmpT;\n\t\t\t}\n\t\t\ttmpThroughputSamples = tmpReport.ThroughputSamples || [];\n\t\t\ttmpEventLog = tmpReport.EventLog || [];\n\t\t}\n\t\telse if (tmpStatusData && tmpStatusData.Tables)\n\t\t{\n\t\t\ttmpTables = tmpStatusData.Tables;\n\t\t\t// Use throughput samples from live status if available (e.g. after page reload with completed sync)\n\t\t\tif (tmpLiveStatus && tmpLiveStatus.ThroughputSamples)\n\t\t\t{\n\t\t\t\ttmpThroughputSamples = tmpLiveStatus.ThroughputSamples;\n\t\t\t}\n\t\t}\n\n\t\t// Categorize tables\n\t\tlet tmpRunning = [];\n\t\tlet tmpPending = [];\n\t\tlet tmpCompleted = [];\n\t\tlet tmpErrors = [];\n\t\tlet tmpTableNames = Object.keys(tmpTables);\n\n\t\tfor (let i = 0; i < tmpTableNames.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpTableNames[i];\n\t\t\tlet tmpT = tmpTables[tmpName];\n\t\t\tif (tmpT.Status === 'Syncing')\n\t\t\t{\n\t\t\t\ttmpRunning.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Pending')\n\t\t\t{\n\t\t\t\ttmpPending.push(tmpName);\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Complete')\n\t\t\t{\n\t\t\t\ttmpCompleted.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Error' || tmpT.Status === 'Partial')\n\t\t\t{\n\t\t\t\ttmpErrors.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t}\n\n\t\tlet tmpHtml = '';\n\n\t\t// === Summary Banner (mirrors collapsed bar counters) ===\n\t\ttmpHtml += this.buildStatusSummaryHtml();\n\n\t\t// === Section 1: Running Operations ===\n\t\tif (tmpRunning.length > 0 || tmpPending.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Running</div>';\n\t\t\tfor (let i = 0; i < tmpRunning.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpOp = tmpRunning[i];\n\t\t\t\tlet tmpPct = tmpOp.Data.Total > 0 ? Math.round((tmpOp.Data.Synced / tmpOp.Data.Total) * 100) : 0;\n\t\t\t\tlet tmpSyncedFmt = this.formatNumber(tmpOp.Data.Synced || 0);\n\t\t\t\tlet tmpTotalFmt = this.formatNumber(tmpOp.Data.Total || 0);\n\t\t\t\ttmpHtml += '<div class=\"running-op-row\">';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-name\">' + this.escapeHtml(tmpOp.Name) + '</div>';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-bar\"><div class=\"running-op-bar-fill\" style=\"width:' + tmpPct + '%\"></div></div>';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-count\">' + tmpSyncedFmt + ' / ' + tmpTotalFmt + ' (' + tmpPct + '%)</div>';\n\t\t\t\ttmpHtml += '</div>';\n\t\t\t}\n\t\t\tif (tmpPending.length > 0)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"running-op-pending\">' + tmpPending.length + ' table' + (tmpPending.length === 1 ? '' : 's') + ' waiting</div>';\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\t// === Section 2: Completed Successful Operations ===\n\t\tif (tmpCompleted.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Completed (' + tmpCompleted.length + ')</div>';\n\n\t\t\tfor (let i = 0; i < tmpCompleted.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += this.renderCompletedRow(tmpCompleted[i]);\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\t// === Section 3: Unsuccessful Operations ===\n\t\tif (tmpErrors.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Errors (' + tmpErrors.length + ')</div>';\n\t\t\tfor (let i = 0; i < tmpErrors.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += this.renderErrorRow(tmpErrors[i], tmpEventLog);\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\tif (tmpHtml === '')\n\t\t{\n\t\t\tif (tmpIsLive)\n\t\t\t{\n\t\t\t\ttmpHtml = '<div style=\"font-size:0.9em; color:#888; padding:8px 0\">Sync in progress, waiting for table data\\u2026</div>';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpHtml = '<div style=\"font-size:0.9em; color:#888; padding:8px 0\">No sync data available. Run a sync to see operation details here.</div>';\n\t\t\t}\n\t\t}\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\n\t\t// Update the throughput histogram via pict-section-histogram\n\t\tthis.updateThroughputHistogram(tmpThroughputSamples);\n\t}\n\n\tupdateThroughputHistogram(pSamples)\n\t{\n\t\tlet tmpHistContainer = document.getElementById('DataCloner-Throughput-Histogram');\n\t\tif (!tmpHistContainer) return;\n\n\t\tif (!pSamples || pSamples.length < 2)\n\t\t{\n\t\t\ttmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// --- Step 1: Compute raw deltas per 10s interval ---\n\t\tlet tmpRawDeltas = [];\n\t\tfor (let i = 1; i < pSamples.length; i++)\n\t\t{\n\t\t\tlet tmpDelta = pSamples[i].synced - pSamples[i - 1].synced;\n\t\t\tif (tmpDelta < 0) tmpDelta = 0;\n\t\t\ttmpRawDeltas.push({ delta: tmpDelta, t: pSamples[i].t });\n\t\t}\n\n\t\t// --- Step 2: Downsample if there are too many bars ---\n\t\tlet tmpContainerWidth = tmpHistContainer.clientWidth || 800;\n\t\tlet tmpMaxBars = Math.max(20, Math.floor(tmpContainerWidth / 6));\n\t\tlet tmpAggregated = tmpRawDeltas;\n\n\t\tif (tmpRawDeltas.length > tmpMaxBars)\n\t\t{\n\t\t\tlet tmpBucketSize = Math.ceil(tmpRawDeltas.length / tmpMaxBars);\n\t\t\ttmpAggregated = [];\n\t\t\tfor (let i = 0; i < tmpRawDeltas.length; i += tmpBucketSize)\n\t\t\t{\n\t\t\t\tlet tmpSum = 0;\n\t\t\t\tlet tmpLastT = 0;\n\t\t\t\tfor (let j = i; j < Math.min(i + tmpBucketSize, tmpRawDeltas.length); j++)\n\t\t\t\t{\n\t\t\t\t\ttmpSum += tmpRawDeltas[j].delta;\n\t\t\t\t\ttmpLastT = tmpRawDeltas[j].t;\n\t\t\t\t}\n\t\t\t\ttmpAggregated.push({ delta: tmpSum, t: tmpLastT });\n\t\t\t}\n\t\t}\n\n\t\t// --- Step 3: Check for data ---\n\t\tlet tmpHasData = false;\n\t\tfor (let i = 0; i < tmpAggregated.length; i++)\n\t\t{\n\t\t\tif (tmpAggregated[i].delta > 0) { tmpHasData = true; break; }\n\t\t}\n\t\tif (!tmpHasData)\n\t\t{\n\t\t\ttmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// --- Step 4: Build bins for the histogram library ---\n\t\tlet tmpStartT = pSamples[0].t;\n\t\tlet tmpBins = [];\n\t\tfor (let i = 0; i < tmpAggregated.length; i++)\n\t\t{\n\t\t\tlet tmpElapsedSec = Math.round((tmpAggregated[i].t - tmpStartT) / 1000);\n\t\t\ttmpBins.push({\n\t\t\t\tLabel: this.formatElapsed(tmpElapsedSec),\n\t\t\t\tValue: tmpAggregated[i].delta\n\t\t\t});\n\t\t}\n\n\t\t// --- Step 5: Update the histogram view via the library ---\n\t\ttmpHistContainer.style.display = '';\n\t\tlet tmpHistView = this.pict.views['DataCloner-StatusHistogram'];\n\t\tif (tmpHistView)\n\t\t{\n\t\t\ttmpHistView.setBins(tmpBins);\n\t\t\ttmpHistView.renderHistogram();\n\t\t}\n\t}\n\n\tbuildStatusSummaryHtml()\n\t{\n\t\tlet tmpLiveStatus = this.pict.AppData.DataCloner.LastLiveStatus;\n\t\tlet tmpReport = this.pict.AppData.DataCloner.LastReport;\n\n\t\tlet tmpParts = [];\n\t\tlet tmpMessage = '';\n\n\t\tif (tmpLiveStatus && (tmpLiveStatus.Phase === 'syncing' || tmpLiveStatus.Phase === 'stopping'))\n\t\t{\n\t\t\ttmpMessage = tmpLiveStatus.Message || '';\n\t\t\tif (tmpLiveStatus.Elapsed)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + this.escapeHtml(tmpLiveStatus.Elapsed) + '</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.ETA)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">~' + this.escapeHtml(tmpLiveStatus.ETA) + ' remaining</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.TotalTables > 0)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpLiveStatus.Completed + '</strong> / ' + tmpLiveStatus.TotalTables + ' tables</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = this.formatNumber(tmpLiveStatus.TotalSynced);\n\t\t\t\tif (tmpLiveStatus.PreCountGrandTotal > 0)\n\t\t\t\t{\n\t\t\t\t\tlet tmpGrandTotal = this.formatNumber(tmpLiveStatus.PreCountGrandTotal);\n\t\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> / ' + tmpGrandTotal + ' records</span>');\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (tmpLiveStatus.PreCountGrandTotal > 0)\n\t\t\t{\n\t\t\t\tlet tmpGrandTotal = this.formatNumber(tmpLiveStatus.PreCountGrandTotal);\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">' + tmpGrandTotal + ' records to sync</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.PreCountProgress && tmpLiveStatus.PreCountProgress.Counted < tmpLiveStatus.PreCountProgress.TotalTables)\n\t\t\t{\n\t\t\t\tlet tmpCountedSoFar = tmpLiveStatus.PreCountGrandTotal > 0\n\t\t\t\t\t? ' (' + this.formatNumber(tmpLiveStatus.PreCountGrandTotal) + ' records found)'\n\t\t\t\t\t: '';\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">counting: ' + tmpLiveStatus.PreCountProgress.Counted + ' / ' + tmpLiveStatus.PreCountProgress.TotalTables + ' tables' + tmpCountedSoFar + '</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.Errors > 0)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\" style=\"color:#dc3545\"><strong>' + tmpLiveStatus.Errors + '</strong> error' + (tmpLiveStatus.Errors === 1 ? '' : 's') + '</span>');\n\t\t\t}\n\t\t}\n\t\telse if (tmpLiveStatus && tmpLiveStatus.Phase === 'complete')\n\t\t{\n\t\t\ttmpMessage = tmpLiveStatus.Message || 'Sync complete';\n\t\t\tif (tmpLiveStatus.Elapsed)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + this.escapeHtml(tmpLiveStatus.Elapsed) + '</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = this.formatNumber(tmpLiveStatus.TotalSynced);\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records synced</span>');\n\t\t\t}\n\t\t}\n\t\telse if (tmpReport && tmpReport.ReportVersion)\n\t\t{\n\t\t\ttmpMessage = 'Sync ' + (tmpReport.Outcome || 'complete').toLowerCase();\n\t\t\tif (tmpReport.RunTimestamps && tmpReport.RunTimestamps.DurationSeconds)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + this.formatElapsed(tmpReport.RunTimestamps.DurationSeconds) + '</span>');\n\t\t\t}\n\t\t\tif (tmpReport.Summary)\n\t\t\t{\n\t\t\t\tif (tmpReport.Summary.TotalSynced > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + this.formatNumber(tmpReport.Summary.TotalSynced) + '</strong> records synced</span>');\n\t\t\t\t}\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpReport.Summary.TotalTables + '</strong> tables</span>');\n\t\t\t\tif (tmpReport.Summary.TotalErrors > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\" style=\"color:#dc3545\"><strong>' + tmpReport.Summary.TotalErrors + '</strong> error' + (tmpReport.Summary.TotalErrors === 1 ? '' : 's') + '</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!tmpMessage && tmpParts.length === 0) return '';\n\n\t\tlet tmpHtml = '<div class=\"status-detail-summary\">';\n\t\tif (tmpMessage)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-summary-message\">' + this.escapeHtml(tmpMessage) + '</div>';\n\t\t}\n\t\tif (tmpParts.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-summary-counters\">' + tmpParts.join('') + '</div>';\n\t\t}\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\tformatElapsed(pSec)\n\t{\n\t\tif (pSec < 60) return pSec + 's';\n\t\tif (pSec < 3600)\n\t\t{\n\t\t\tlet tmpM = Math.floor(pSec / 60);\n\t\t\tlet tmpS = pSec % 60;\n\t\t\treturn tmpM + ':' + (tmpS < 10 ? '0' : '') + tmpS;\n\t\t}\n\t\tlet tmpH = Math.floor(pSec / 3600);\n\t\tlet tmpM = Math.floor((pSec % 3600) / 60);\n\t\treturn tmpH + 'h' + (tmpM < 10 ? '0' : '') + tmpM;\n\t}\n\n\tformatCompact(pNum)\n\t{\n\t\tif (pNum >= 1000000) return (pNum / 1000000).toFixed(1) + 'M';\n\t\tif (pNum >= 10000) return (pNum / 1000).toFixed(0) + 'K';\n\t\tif (pNum >= 1000) return (pNum / 1000).toFixed(1) + 'K';\n\t\treturn pNum.toString();\n\t}\n\n\tformatNumber(pNum)\n\t{\n\t\treturn pNum.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t}\n\n\trenderCompletedRow(pOp)\n\t{\n\t\tlet tmpNew = pOp.Data.New || 0;\n\t\tlet tmpUpdated = pOp.Data.Updated || 0;\n\t\tlet tmpUnchanged = pOp.Data.Unchanged || 0;\n\t\tlet tmpDeleted = pOp.Data.Deleted || 0;\n\t\tlet tmpServerTotal = pOp.Data.ServerTotal || 0;\n\n\t\t// Grand total for the ratio bar: all records the adapter dealt with\n\t\tlet tmpGrandTotal = tmpUnchanged + tmpNew + tmpUpdated + tmpDeleted;\n\t\tif (tmpGrandTotal === 0 && tmpServerTotal > 0)\n\t\t{\n\t\t\ttmpGrandTotal = tmpServerTotal;\n\t\t\ttmpUnchanged = tmpServerTotal;\n\t\t}\n\n\t\tlet tmpHtml = '<div class=\"completed-op-row\">';\n\t\ttmpHtml += '<div class=\"completed-op-header\">';\n\t\ttmpHtml += ' <span class=\"completed-op-checkmark\">\\u2713</span>';\n\t\ttmpHtml += ' <span class=\"completed-op-name\">' + this.escapeHtml(pOp.Name) + '</span>';\n\t\ttmpHtml += '</div>';\n\n\t\t// Ratio bar: Unchanged / New / Updated / Deleted\n\t\tif (tmpGrandTotal > 0)\n\t\t{\n\t\t\tlet tmpUnchangedPct = Math.round((tmpUnchanged / tmpGrandTotal) * 100);\n\t\t\tlet tmpNewPct = Math.round((tmpNew / tmpGrandTotal) * 100);\n\t\t\tlet tmpUpdatedPct = Math.round((tmpUpdated / tmpGrandTotal) * 100);\n\t\t\tlet tmpDeletedPct = Math.round((tmpDeleted / tmpGrandTotal) * 100);\n\n\t\t\t// Ensure percentages sum to 100\n\t\t\tlet tmpPctSum = tmpUnchangedPct + tmpNewPct + tmpUpdatedPct + tmpDeletedPct;\n\t\t\tif (tmpPctSum !== 100 && tmpPctSum > 0)\n\t\t\t{\n\t\t\t\ttmpUnchangedPct += (100 - tmpPctSum);\n\t\t\t\tif (tmpUnchangedPct < 0) tmpUnchangedPct = 0;\n\t\t\t}\n\n\t\t\ttmpHtml += '<div class=\"ratio-bar-container\">';\n\t\t\tif (tmpUnchangedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment unchanged\" style=\"width:' + tmpUnchangedPct + '%\" title=\"Unchanged: ' + this.formatNumber(tmpUnchanged) + '\"></div>';\n\t\t\tif (tmpNewPct > 0) tmpHtml += '<div class=\"ratio-bar-segment new-records\" style=\"width:' + tmpNewPct + '%\" title=\"New: ' + this.formatNumber(tmpNew) + '\"></div>';\n\t\t\tif (tmpUpdatedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment updated\" style=\"width:' + tmpUpdatedPct + '%\" title=\"Updated: ' + this.formatNumber(tmpUpdated) + '\"></div>';\n\t\t\tif (tmpDeletedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment deleted\" style=\"width:' + tmpDeletedPct + '%\" title=\"Deleted: ' + this.formatNumber(tmpDeleted) + '\"></div>';\n\t\t\ttmpHtml += '</div>';\n\n\t\t\ttmpHtml += '<div class=\"ratio-bar-legend\">';\n\t\t\tif (tmpUnchanged > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot unchanged-dot\"></span> Unchanged (' + this.formatNumber(tmpUnchanged) + ')</span>';\n\t\t\tif (tmpNew > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot new-dot\"></span> New (' + this.formatNumber(tmpNew) + ')</span>';\n\t\t\tif (tmpUpdated > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot updated-dot\"></span> Updated (' + this.formatNumber(tmpUpdated) + ')</span>';\n\t\t\tif (tmpDeleted > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot deleted-dot\"></span> Deleted (' + this.formatNumber(tmpDeleted) + ')</span>';\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\trenderErrorRow(pOp, pEventLog)\n\t{\n\t\tlet tmpSynced = pOp.Data.Synced || 0;\n\t\tlet tmpTotal = pOp.Data.Total || 0;\n\t\tlet tmpSyncedFmt = this.formatNumber(tmpSynced);\n\t\tlet tmpTotalFmt = this.formatNumber(tmpTotal);\n\n\t\tlet tmpHtml = '<div class=\"error-op-row\">';\n\t\ttmpHtml += '<div class=\"error-op-header\">';\n\t\ttmpHtml += ' <span style=\"color:#dc3545\">\\u2717</span>';\n\t\ttmpHtml += ' <span class=\"error-op-name\">' + this.escapeHtml(pOp.Name) + '</span>';\n\t\ttmpHtml += ' <span class=\"error-op-status\">' + pOp.Data.Status + ' \\u2014 ' + tmpSyncedFmt + ' / ' + tmpTotalFmt + '</span>';\n\t\ttmpHtml += '</div>';\n\n\t\tif (pOp.Data.ErrorMessage)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"error-op-message\">' + this.escapeHtml(pOp.Data.ErrorMessage) + '</div>';\n\t\t}\n\n\t\t// Extract relevant log entries from EventLog\n\t\tif (pEventLog && pEventLog.length > 0)\n\t\t{\n\t\t\tlet tmpRelevantLogs = [];\n\t\t\tfor (let j = 0; j < pEventLog.length; j++)\n\t\t\t{\n\t\t\t\tlet tmpLog = pEventLog[j];\n\t\t\t\tif (tmpLog.Data && tmpLog.Data.Table === pOp.Name &&\n\t\t\t\t\t(tmpLog.Type === 'TableError' || tmpLog.Type === 'TablePartial'))\n\t\t\t\t{\n\t\t\t\t\ttmpRelevantLogs.push(tmpLog);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tmpRelevantLogs.length > 0)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"error-op-log-entries\">';\n\t\t\t\tfor (let j = 0; j < tmpRelevantLogs.length; j++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpTimestamp = tmpRelevantLogs[j].Timestamp.replace('T', ' ').replace(/\\.\\d+Z$/, '');\n\t\t\t\t\ttmpHtml += '<div>' + this.escapeHtml(tmpTimestamp + ' ' + tmpRelevantLogs[j].Message) + '</div>';\n\t\t\t\t}\n\t\t\t\ttmpHtml += '</div>';\n\t\t\t}\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\t// ================================================================\n\t// Deployed Tables Persistence\n\t// ================================================================\n\n\tsaveDeployedTables()\n\t{\n\t\tlocalStorage.setItem('dataCloner_deployedTables', JSON.stringify(this.pict.AppData.DataCloner.DeployedTables));\n\t}\n\n\trestoreDeployedTables()\n\t{\n\t\ttry\n\t\t{\n\t\t\tlet tmpRaw = localStorage.getItem('dataCloner_deployedTables');\n\t\t\tif (tmpRaw)\n\t\t\t{\n\t\t\t\tthis.pict.AppData.DataCloner.DeployedTables = JSON.parse(tmpRaw);\n\t\t\t\tthis.pict.views['DataCloner-ViewData'].populateViewTableDropdown();\n\t\t\t}\n\t\t}\n\t\tcatch (pError) { /* ignore */ }\n\t}\n\n\t// ================================================================\n\t// Auto-Process\n\t// ================================================================\n\n\tinitAutoProcess()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/live-status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Phase === 'syncing' || pData.Phase === 'stopping')\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.ServerBusyAtLoad = true;\n\t\t\t\t\ttmpSelf.setSectionPhase(5, 'busy');\n\t\t\t\t\ttmpSelf.pict.views['DataCloner-Sync'].startPolling();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttmpSelf.runAutoProcessChain();\n\t\t\t})\n\t\t\t.catch(function()\n\t\t\t{\n\t\t\t\t// Server unreachable — don't auto-process\n\t\t\t});\n\t}\n\n\trunAutoProcessChain()\n\t{\n\t\tlet tmpSelf = this;\n\t\tlet tmpDelay = 0;\n\t\tlet tmpStepDelay = 2000;\n\n\t\tif (document.getElementById('auto1') && document.getElementById('auto1').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Connection'].connectProvider(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto2') && document.getElementById('auto2').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Session'].goAction(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay + 1500;\n\t\t}\n\t\tif (document.getElementById('auto3') && document.getElementById('auto3').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Schema'].fetchSchema(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto4') && document.getElementById('auto4').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Deploy'].deploySchema(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto5') && document.getElementById('auto5').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Sync'].startSync(); }, tmpDelay);\n\t\t}\n\t}\n}\n\nmodule.exports = DataClonerProvider;\n\nmodule.exports.default_configuration =\n{\n\tProviderIdentifier: 'DataCloner',\n\tAutoInitialize: true,\n\tAutoInitializeOrdinal: 0\n};\n\n},{\"pict-provider\":6}],19:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerConnectionView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tonProviderChange()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpProviders = ['SQLite', 'MySQL', 'MSSQL', 'PostgreSQL', 'Solr', 'MongoDB', 'RocksDB', 'Bibliograph'];\n\t\tfor (let i = 0; i < tmpProviders.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById('config' + tmpProviders[i]);\n\t\t\tif (tmpEl)\n\t\t\t{\n\t\t\t\ttmpEl.style.display = (tmpProvider === tmpProviders[i]) ? '' : 'none';\n\t\t\t}\n\t\t}\n\t\tthis.pict.providers.DataCloner.saveField('connProvider');\n\t}\n\n\tgetProviderConfig()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\ttmpConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || '~/headlight-liveconnect-local/cloned.sqlite';\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpConfig.password = document.getElementById('mysqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mysqlDatabase').value.trim();\n\t\t\ttmpConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpConfig.password = document.getElementById('mssqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mssqlDatabase').value.trim();\n\t\t\ttmpConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;\n\t\t\ttmpConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';\n\t\t\ttmpConfig.password = document.getElementById('postgresqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('postgresqlDatabase').value.trim();\n\t\t\ttmpConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;\n\t\t}\n\t\telse if (tmpProvider === 'Solr')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('solrHost').value.trim() || 'localhost';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('solrPort').value, 10) || 8983;\n\t\t\ttmpConfig.core = document.getElementById('solrCore').value.trim() || 'default';\n\t\t\ttmpConfig.path = document.getElementById('solrPath').value.trim() || '/solr';\n\t\t\ttmpConfig.secure = document.getElementById('solrSecure').checked;\n\t\t}\n\t\telse if (tmpProvider === 'MongoDB')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('mongodbHost').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mongodbPort').value, 10) || 27017;\n\t\t\ttmpConfig.user = document.getElementById('mongodbUser').value.trim();\n\t\t\ttmpConfig.password = document.getElementById('mongodbPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mongodbDatabase').value.trim() || 'test';\n\t\t\ttmpConfig.maxPoolSize = parseInt(document.getElementById('mongodbConnectionLimit').value, 10) || 10;\n\t\t}\n\t\telse if (tmpProvider === 'RocksDB')\n\t\t{\n\t\t\ttmpConfig.RocksDBFolder = document.getElementById('rocksdbFolder').value.trim() || 'data/rocksdb';\n\t\t}\n\t\telse if (tmpProvider === 'Bibliograph')\n\t\t{\n\t\t\ttmpConfig.StorageFolder = document.getElementById('bibliographFolder').value.trim() || 'data/bibliograph';\n\t\t}\n\n\t\treturn { Provider: tmpProvider, Config: tmpConfig };\n\t}\n\n\tconnectProvider()\n\t{\n\t\t// Guard against re-entrant calls (e.g. rapid auto-connect polling)\n\t\tif (this._connectInFlight)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tthis._connectInFlight = true;\n\n\t\tlet tmpConnInfo = this.getProviderConfig();\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connecting to ' + tmpConnInfo.Provider + '...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/connection/configure', tmpConnInfo)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\ttmpSelf._connectInFlight = false;\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');\n\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(1, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('connectionStatus', 'Connection failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(1, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\ttmpSelf._connectInFlight = false;\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(1, 'error');\n\t\t\t\t});\n\t}\n\n\ttestConnection()\n\t{\n\t\tlet tmpConnInfo = this.getProviderConfig();\n\n\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Testing ' + tmpConnInfo.Provider + ' connection...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/connection/test', tmpConnInfo)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Test failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tcheckConnectionStatus()\n\t{\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/connection/status')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Connected)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connected: ' + pData.Provider, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'ok');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t() =>\n\t\t\t\t{\n\t\t\t\t\t/* ignore */\n\t\t\t\t});\n\t}\n}\n\nmodule.exports = DataClonerConnectionView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Connection',\n\tDefaultRenderable: 'DataCloner-Connection',\n\tDefaultDestinationAddress: '#DataCloner-Section-Connection',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Connection',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">1</div>\n\t<div class=\"accordion-card\" id=\"section1\" data-section=\"1\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section1')\">\n\t\t\t<div class=\"accordion-title\">Database Connection</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase1\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview1\">SQLite at data/cloned.sqlite</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Connection'].connectProvider()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto1\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Configure the local database where cloned data will be stored. SQLite is connected by default.</p>\n\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:0 0 200px\">\n\t\t\t\t\t<label for=\"connProvider\">Provider</label>\n\t\t\t\t\t<select id=\"connProvider\" onchange=\"pict.views['DataCloner-Connection'].onProviderChange()\">\n\t\t\t\t\t\t<option value=\"SQLite\" selected>SQLite</option>\n\t\t\t\t\t\t<option value=\"MySQL\">MySQL</option>\n\t\t\t\t\t\t<option value=\"MSSQL\">MSSQL</option>\n\t\t\t\t\t\t<option value=\"PostgreSQL\">PostgreSQL</option>\n\t\t\t\t\t\t<option value=\"Solr\">Solr</option>\n\t\t\t\t\t\t<option value=\"MongoDB\">MongoDB</option>\n\t\t\t\t\t\t<option value=\"RocksDB\">RocksDB</option>\n\t\t\t\t\t\t<option value=\"Bibliograph\">Bibliograph</option>\n\t\t\t\t\t</select>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:1; display:flex; align-items:flex-end; gap:8px\">\n\t\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Connection'].connectProvider()\">Connect</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Connection'].testConnection()\">Test Connection</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- SQLite Config -->\n\t\t\t<div id=\"configSQLite\">\n\t\t\t\t<label for=\"sqliteFilePath\">SQLite File Path</label>\n\t\t\t\t<input type=\"text\" id=\"sqliteFilePath\" placeholder=\"~/headlight-liveconnect-local/cloned.sqlite\" value=\"~/headlight-liveconnect-local/cloned.sqlite\">\n\t\t\t</div>\n\n\t\t\t<!-- MySQL Config -->\n\t\t\t<div id=\"configMySQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mysqlServer\">Server</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mysqlServer\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mysqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mysqlPort\" placeholder=\"3306\" value=\"3306\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mysqlUser\" placeholder=\"root\" value=\"root\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mysqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mysqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mysqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlConnectionLimit\">Connection Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mysqlConnectionLimit\" placeholder=\"20\" value=\"20\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- MSSQL Config -->\n\t\t\t<div id=\"configMSSQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mssqlServer\">Server</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mssqlServer\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mssqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mssqlPort\" placeholder=\"1433\" value=\"1433\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mssqlUser\" placeholder=\"sa\" value=\"sa\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mssqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mssqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mssqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlConnectionLimit\">Connection Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mssqlConnectionLimit\" placeholder=\"20\" value=\"20\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- PostgreSQL Config -->\n\t\t\t<div id=\"configPostgreSQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"postgresqlHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"postgresqlHost\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"postgresqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"postgresqlPort\" placeholder=\"5432\" value=\"5432\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"postgresqlUser\" placeholder=\"postgres\" value=\"postgres\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"postgresqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"postgresqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"postgresqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlConnectionLimit\">Connection Pool Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"postgresqlConnectionLimit\" placeholder=\"10\" value=\"10\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- Solr Config -->\n\t\t\t<div id=\"configSolr\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"solrHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrHost\" placeholder=\"localhost\" value=\"localhost\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"solrPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"solrPort\" placeholder=\"8983\" value=\"8983\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"solrCore\">Core</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrCore\" placeholder=\"default\" value=\"default\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"solrPath\">Path</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrPath\" placeholder=\"/solr\" value=\"/solr\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t\t<input type=\"checkbox\" id=\"solrSecure\">\n\t\t\t\t\t<label for=\"solrSecure\">Use HTTPS</label>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- MongoDB Config -->\n\t\t\t<div id=\"configMongoDB\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mongodbHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mongodbHost\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mongodbPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mongodbPort\" placeholder=\"27017\" value=\"27017\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mongodbUser\" placeholder=\"(optional)\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mongodbPassword\" placeholder=\"(optional)\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mongodbDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mongodbDatabase\" placeholder=\"test\" value=\"test\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbConnectionLimit\">Max Pool Size</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mongodbConnectionLimit\" placeholder=\"10\" value=\"10\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- RocksDB Config -->\n\t\t\t<div id=\"configRocksDB\" style=\"display:none\">\n\t\t\t\t<label for=\"rocksdbFolder\">RocksDB Folder Path</label>\n\t\t\t\t<input type=\"text\" id=\"rocksdbFolder\" placeholder=\"data/rocksdb\" value=\"data/rocksdb\">\n\t\t\t</div>\n\n\t\t\t<!-- Bibliograph Config -->\n\t\t\t<div id=\"configBibliograph\" style=\"display:none\">\n\t\t\t\t<label for=\"bibliographFolder\">Storage Folder Path</label>\n\t\t\t\t<input type=\"text\" id=\"bibliographFolder\" placeholder=\"data/bibliograph\" value=\"data/bibliograph\">\n\t\t\t</div>\n\n\t\t\t<div id=\"connectionStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Connection',\n\t\t\tTemplateHash: 'DataCloner-Connection',\n\t\t\tDestinationAddress: '#DataCloner-Section-Connection'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],20:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerDeployView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tdeploySchema()\n\t{\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\n\t\tif (tmpSelectedTables.length === 0)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'No tables selected. Fetch a schema and select tables first.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(4, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'Deploying ' + tmpSelectedTables.length + ' tables...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/deploy', { Tables: tmpSelectedTables })\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\tlet tmpStatusMsg = pData.Message;\n\n\t\t\t\t\t// Append migration details if schema deltas were applied\n\t\t\t\t\tif (Array.isArray(pData.MigrationsApplied) && pData.MigrationsApplied.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tlet tmpDetails = pData.MigrationsApplied.map(function(pM)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn pM.Table + ': +' + pM.ColumnsAdded.join(', +');\n\t\t\t\t\t\t});\n\t\t\t\t\t\ttmpStatusMsg += '\\nMigrations: ' + tmpDetails.join('; ');\n\t\t\t\t\t}\n\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', tmpStatusMsg, 'ok');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'ok');\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.DeployedTables = pData.TablesDeployed || tmpSelectedTables;\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.saveDeployedTables();\n\t\t\t\t\ttmpSelf.pict.views['DataCloner-ViewData'].populateViewTableDropdown();\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.updateAllPreviews();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Deploy failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\t});\n\t}\n\n\tauditGUIDIndices()\n\t{\n\t\tlet tmpReportEl = document.getElementById('guidIndexReport');\n\t\tif (tmpReportEl) tmpReportEl.innerHTML = '<span style=\"color:#888\">Checking GUID indices...</span>';\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/schema/guid-index-audit')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (!tmpReportEl) return;\n\n\t\t\t\tif (!pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpReportEl.innerHTML = '<span style=\"color:red\">' + (pData.Error || 'Audit failed') + '</span>';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (pData.MissingCount === 0)\n\t\t\t\t{\n\t\t\t\t\ttmpReportEl.innerHTML = '<span style=\"color:green\">All GUID columns have indices.</span>';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet tmpHTML = '<div style=\"margin-top:6px\"><strong>' + pData.Message + '</strong></div>';\n\t\t\t\ttmpHTML += '<table style=\"font-size:0.85em; margin:6px 0; border-collapse:collapse; width:100%\">';\n\t\t\t\ttmpHTML += '<tr style=\"text-align:left; border-bottom:1px solid #ccc\"><th style=\"padding:3px 8px\">Table</th><th style=\"padding:3px 8px\">GUID Column</th><th style=\"padding:3px 8px\">Index</th></tr>';\n\n\t\t\t\tfor (let t = 0; t < pData.Tables.length; t++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpTable = pData.Tables[t];\n\t\t\t\t\tfor (let c = 0; c < tmpTable.GUIDColumns.length; c++)\n\t\t\t\t\t{\n\t\t\t\t\t\tlet tmpCol = tmpTable.GUIDColumns[c];\n\t\t\t\t\t\tlet tmpStatus = tmpCol.HasIndex\n\t\t\t\t\t\t\t? '<span style=\"color:green\">' + tmpCol.IndexName + '</span>'\n\t\t\t\t\t\t\t: '<span style=\"color:red\">MISSING</span>';\n\t\t\t\t\t\ttmpHTML += '<tr style=\"border-bottom:1px solid #eee\"><td style=\"padding:3px 8px\">' + tmpTable.Table + '</td><td style=\"padding:3px 8px\">' + tmpCol.Column + '</td><td style=\"padding:3px 8px\">' + tmpStatus + '</td></tr>';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttmpHTML += '</table>';\n\t\t\t\ttmpHTML += '<button class=\"primary\" style=\"margin-top:4px\" onclick=\"pict.views[\\'DataCloner-Deploy\\'].createMissingGUIDIndices()\">Create Missing Indices</button>';\n\n\t\t\t\ttmpReportEl.innerHTML = tmpHTML;\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\tif (tmpReportEl) tmpReportEl.innerHTML = '<span style=\"color:red\">Request failed: ' + pError.message + '</span>';\n\t\t\t});\n\t}\n\n\tcreateMissingGUIDIndices()\n\t{\n\t\tlet tmpReportEl = document.getElementById('guidIndexReport');\n\t\tif (tmpReportEl) tmpReportEl.innerHTML = '<span style=\"color:#888\">Creating GUID indices...</span>';\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/guid-index-create')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (!tmpReportEl) return;\n\n\t\t\t\tif (!pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpReportEl.innerHTML = '<span style=\"color:red\">' + (pData.Error || 'Index creation failed') + '</span>';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet tmpHTML = '<div style=\"margin-top:6px; color:green\"><strong>' + pData.Message + '</strong></div>';\n\n\t\t\t\tif (pData.IndicesCreated && pData.IndicesCreated.length > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpHTML += '<ul style=\"font-size:0.85em; margin:4px 0\">';\n\t\t\t\t\tfor (let i = 0; i < pData.IndicesCreated.length; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tlet tmpIdx = pData.IndicesCreated[i];\n\t\t\t\t\t\ttmpHTML += '<li>' + tmpIdx.Table + ': ' + tmpIdx.IndexName + '</li>';\n\t\t\t\t\t}\n\t\t\t\t\ttmpHTML += '</ul>';\n\t\t\t\t}\n\n\t\t\t\ttmpHTML += '<button style=\"margin-top:4px\" onclick=\"pict.views[\\'DataCloner-Deploy\\'].auditGUIDIndices()\">Re-check</button>';\n\t\t\t\ttmpReportEl.innerHTML = tmpHTML;\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\tif (tmpReportEl) tmpReportEl.innerHTML = '<span style=\"color:red\">Request failed: ' + pError.message + '</span>';\n\t\t\t});\n\t}\n\n\tresetDatabase()\n\t{\n\t\tif (!confirm('This will delete ALL data in the local SQLite database. Continue?'))\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'Resetting database...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/reset')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', pData.Message, 'ok');\n\t\t\t\t\t// Clear the sync progress display\n\t\t\t\t\tlet tmpSyncProgress = document.getElementById('syncProgress');\n\t\t\t\t\tif (tmpSyncProgress) tmpSyncProgress.innerHTML = '';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Reset failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n}\n\nmodule.exports = DataClonerDeployView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Deploy',\n\tDefaultRenderable: 'DataCloner-Deploy',\n\tDefaultDestinationAddress: '#DataCloner-Section-Deploy',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Deploy',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">4</div>\n\t<div class=\"accordion-card\" id=\"section4\" data-section=\"4\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section4')\">\n\t\t\t<div class=\"accordion-title\">Deploy Schema</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase4\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview4\">Create selected tables in the local database</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Deploy'].deploySchema()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto4\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Creates the selected tables in the local database and sets up CRUD endpoints (e.g. GET /1.0/Documents).</p>\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Deploy'].deploySchema()\">Deploy Selected Tables</button>\n\t\t\t<button onclick=\"pict.views['DataCloner-Deploy'].auditGUIDIndices()\">Check GUID Indices</button>\n\t\t\t<button class=\"danger\" onclick=\"pict.views['DataCloner-Deploy'].resetDatabase()\">Reset Database</button>\n\t\t\t<div id=\"deployStatus\"></div>\n\t\t\t<div id=\"guidIndexReport\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Deploy',\n\t\t\tTemplateHash: 'DataCloner-Deploy',\n\t\t\tDestinationAddress: '#DataCloner-Section-Deploy'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],21:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerExportView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tbuildConfigObject()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\t// ---- Local Database ----\n\t\ttmpConfig.LocalDatabase = { Provider: tmpProvider, Config: {} };\n\t\tlet tmpDbConfig = tmpConfig.LocalDatabase.Config;\n\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\ttmpDbConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || '~/headlight-liveconnect-local/cloned.sqlite';\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpDbConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpDbConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpDbConfig.password = document.getElementById('mysqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('mysqlDatabase').value.trim();\n\t\t\ttmpDbConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpDbConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpDbConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpDbConfig.password = document.getElementById('mssqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('mssqlDatabase').value.trim();\n\t\t\ttmpDbConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\ttmpDbConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;\n\t\t\ttmpDbConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';\n\t\t\ttmpDbConfig.password = document.getElementById('postgresqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('postgresqlDatabase').value.trim();\n\t\t\ttmpDbConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;\n\t\t}\n\n\t\t// ---- Remote Session ----\n\t\ttmpConfig.RemoteSession = {};\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\tif (tmpServerURL) tmpConfig.RemoteSession.ServerURL = tmpServerURL + '/1.0/';\n\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim();\n\t\tif (tmpAuthMethod) tmpConfig.RemoteSession.AuthenticationMethod = tmpAuthMethod;\n\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI) tmpConfig.RemoteSession.AuthenticationURITemplate = tmpAuthURI;\n\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI) tmpConfig.RemoteSession.CheckSessionURITemplate = tmpCheckURI;\n\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\tif (tmpCookieName) tmpConfig.RemoteSession.CookieName = tmpCookieName;\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr) tmpConfig.RemoteSession.CookieValueAddress = tmpCookieValueAddr;\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate) tmpConfig.RemoteSession.CookieValueTemplate = tmpCookieValueTemplate;\n\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\tif (tmpLoginMarker) tmpConfig.RemoteSession.CheckSessionLoginMarker = tmpLoginMarker;\n\n\t\t// ---- Credentials ----\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value;\n\t\tif (tmpUserName || tmpPassword)\n\t\t{\n\t\t\ttmpConfig.Credentials = {};\n\t\t\tif (tmpUserName) tmpConfig.Credentials.UserName = tmpUserName;\n\t\t\tif (tmpPassword) tmpConfig.Credentials.Password = tmpPassword;\n\t\t}\n\n\t\t// ---- Schema ----\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tif (tmpSchemaURL) tmpConfig.SchemaURL = tmpSchemaURL;\n\n\t\t// ---- Tables ----\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\tif (tmpSelectedTables.length > 0) tmpConfig.Tables = tmpSelectedTables;\n\n\t\t// ---- Sync Options ----\n\t\ttmpConfig.Sync = {};\n\t\ttmpConfig.Sync.Mode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\ttmpConfig.Sync.PageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\ttmpConfig.Sync.SyncDeletedRecords = document.getElementById('syncDeletedRecords').checked;\n\t\tlet tmpPrecision = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (!isNaN(tmpPrecision) && tmpPrecision !== 1000) tmpConfig.Sync.DateTimePrecisionMS = tmpPrecision;\n\t\tlet tmpMaxRecords = parseInt(document.getElementById('syncMaxRecords').value, 10);\n\t\tif (tmpMaxRecords > 0) tmpConfig.Sync.MaxRecords = tmpMaxRecords;\n\t\tif (document.getElementById('syncAdvancedIDPagination').checked) tmpConfig.Sync.UseAdvancedIDPagination = true;\n\n\t\treturn tmpConfig;\n\t}\n\n\tbuildMeadowIntegrationConfig()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\t// ---- Source ----\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\ttmpConfig.Source = { ServerURL: tmpServerURL ? tmpServerURL + '/1.0/' : 'https://localhost:8080/1.0/' };\n\t\t// When SessionManager handles auth, Source credentials are not needed\n\t\ttmpConfig.Source.UserID = false;\n\t\ttmpConfig.Source.Password = false;\n\n\t\t// ---- Destination ----\n\t\t// meadow-integration clone supports MySQL and MSSQL\n\t\ttmpConfig.Destination = {};\n\t\tif (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpConfig.Destination.Provider = 'MySQL';\n\t\t\ttmpConfig.Destination.MySQL = {};\n\t\t\ttmpConfig.Destination.MySQL.server = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.Destination.MySQL.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpConfig.Destination.MySQL.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpConfig.Destination.MySQL.password = document.getElementById('mysqlPassword').value || '';\n\t\t\ttmpConfig.Destination.MySQL.database = document.getElementById('mysqlDatabase').value.trim() || 'meadow';\n\t\t\ttmpConfig.Destination.MySQL.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpConfig.Destination.Provider = 'MSSQL';\n\t\t\ttmpConfig.Destination.MSSQL = {};\n\t\t\ttmpConfig.Destination.MSSQL.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.Destination.MSSQL.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpConfig.Destination.MSSQL.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpConfig.Destination.MSSQL.password = document.getElementById('mssqlPassword').value || '';\n\t\t\ttmpConfig.Destination.MSSQL.database = document.getElementById('mssqlDatabase').value.trim() || 'meadow';\n\t\t\ttmpConfig.Destination.MSSQL.ConnectionPoolLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Default to MySQL placeholder for unsupported providers\n\t\t\ttmpConfig.Destination.Provider = 'MySQL';\n\t\t\ttmpConfig.Destination.MySQL = { server: '127.0.0.1', port: 3306, user: 'root', password: '', database: 'meadow', connectionLimit: 20 };\n\t\t}\n\n\t\t// ---- Schema ----\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tif (tmpSchemaURL)\n\t\t{\n\t\t\ttmpConfig.SchemaURL = tmpSchemaURL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpConfig.SchemaPath = './schema/Model-Extended.json';\n\t\t}\n\n\t\t// ---- Sync ----\n\t\ttmpConfig.Sync = {};\n\t\ttmpConfig.Sync.DefaultSyncMode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\ttmpConfig.Sync.PageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\tlet tmpMdwintPrecision = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (!isNaN(tmpMdwintPrecision)) tmpConfig.Sync.DateTimePrecisionMS = tmpMdwintPrecision;\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\ttmpConfig.Sync.SyncEntityList = tmpSelectedTables.length > 0 ? tmpSelectedTables : [];\n\t\ttmpConfig.Sync.SyncEntityOptions = {};\n\t\tif (document.getElementById('syncAdvancedIDPagination').checked) tmpConfig.Sync.UseAdvancedIDPagination = true;\n\n\t\t// ---- SessionManager ----\n\t\ttmpConfig.SessionManager = { Sessions: {} };\n\n\t\tlet tmpSessionConfig = {};\n\t\ttmpSessionConfig.Type = 'Cookie';\n\n\t\t// Authentication method\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim() || 'get';\n\t\ttmpSessionConfig.AuthenticationMethod = tmpAuthMethod;\n\n\t\t// Build the authentication URI template\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI)\n\t\t{\n\t\t\t// If the URI is a relative path, prepend the server URL\n\t\t\tif (tmpAuthURI.charAt(0) === '/')\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = (tmpServerURL || '') + tmpAuthURI;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpAuthURI;\n\t\t\t}\n\t\t}\n\t\telse if (tmpServerURL)\n\t\t{\n\t\t\t// Default: Meadow-style GET authentication\n\t\t\tif (tmpAuthMethod === 'post')\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpServerURL + '/1.0/Authenticate';\n\t\t\t\ttmpSessionConfig.AuthenticationRequestBody = {\n\t\t\t\t\tUserName: '{~D:Record.UserName~}',\n\t\t\t\t\tPassword: '{~D:Record.Password~}'\n\t\t\t\t};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpServerURL + '/1.0/Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}';\n\t\t\t}\n\t\t}\n\n\t\t// Check session URI\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI)\n\t\t{\n\t\t\ttmpSessionConfig.CheckSessionURITemplate = tmpCheckURI.charAt(0) === '/' ? (tmpServerURL || '') + tmpCheckURI : tmpCheckURI;\n\t\t}\n\t\telse if (tmpServerURL)\n\t\t{\n\t\t\ttmpSessionConfig.CheckSessionURITemplate = tmpServerURL + '/1.0/CheckSession';\n\t\t}\n\n\t\t// Login marker\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\ttmpSessionConfig.CheckSessionLoginMarkerType = 'boolean';\n\t\ttmpSessionConfig.CheckSessionLoginMarker = tmpLoginMarker || 'LoggedIn';\n\n\t\t// Domain match — extract from server URL for auto-injection\n\t\tif (tmpServerURL)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tlet tmpUrlObj = new URL(tmpServerURL);\n\t\t\t\ttmpSessionConfig.DomainMatch = tmpUrlObj.host;\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\ttmpSessionConfig.DomainMatch = tmpServerURL;\n\t\t\t}\n\t\t}\n\n\t\t// Cookie injection\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\ttmpSessionConfig.CookieName = tmpCookieName || 'SessionID';\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr) tmpSessionConfig.CookieValueAddress = tmpCookieValueAddr;\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate) tmpSessionConfig.CookieValueTemplate = tmpCookieValueTemplate;\n\n\t\t// Credentials\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value;\n\t\ttmpSessionConfig.Credentials = {};\n\t\tif (tmpUserName) tmpSessionConfig.Credentials.UserName = tmpUserName;\n\t\tif (tmpPassword) tmpSessionConfig.Credentials.Password = tmpPassword;\n\n\t\ttmpConfig.SessionManager.Sessions.SourceAPI = tmpSessionConfig;\n\n\t\treturn tmpConfig;\n\t}\n\n\tgenerateConfig()\n\t{\n\t\tlet tmpConfig = this.buildConfigObject();\n\t\tlet tmpJson = JSON.stringify(tmpConfig, null, '\\t');\n\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\ttmpTextarea.value = tmpJson;\n\t\ttmpTextarea.style.display = '';\n\n\t\t// Build CLI flags from export options\n\t\tlet tmpLogFlag = document.getElementById('syncLogFile').checked ? ' --log' : '';\n\t\tlet tmpMaxFlag = '';\n\t\tlet tmpExportMax = parseInt(document.getElementById('syncMaxRecords').value, 10);\n\t\tif (tmpExportMax > 0) tmpMaxFlag = ' --max ' + tmpExportMax;\n\n\t\t// Build CLI command (with config file)\n\t\tlet tmpCliDiv = document.getElementById('cliCommand');\n\t\ttmpCliDiv.style.display = '';\n\t\ttmpCliDiv.querySelector('div').textContent = 'npx retold-data-service-clone --config clone-config.json --run' + tmpLogFlag + tmpMaxFlag;\n\n\t\t// Build one-liner (no config file needed) using --config-json\n\t\tlet tmpOneShotDiv = document.getElementById('cliOneShot');\n\t\ttmpOneShotDiv.style.display = '';\n\t\tlet tmpCompactJSON = JSON.stringify(tmpConfig);\n\t\t// Escape single quotes for shell wrapping\n\t\tlet tmpEscapedJSON = tmpCompactJSON.replace(/'/g, \"'\\\\''\");\n\t\tlet tmpOneShot = \"npx retold-data-service-clone --config-json '\" + tmpEscapedJSON + \"' --run\" + tmpLogFlag + tmpMaxFlag;\n\t\ttmpOneShotDiv.querySelector('div').textContent = tmpOneShot;\n\n\t\t// ---- meadow-integration (mdwint clone) config ----\n\t\tlet tmpMdwintConfig = this.buildMeadowIntegrationConfig();\n\t\tlet tmpMdwintJSON = JSON.stringify(tmpMdwintConfig, null, '\\t');\n\n\t\tlet tmpMdwintDiv = document.getElementById('mdwintExport');\n\t\ttmpMdwintDiv.style.display = '';\n\n\t\tlet tmpMdwintTextarea = document.getElementById('mdwintConfigOutput');\n\t\ttmpMdwintTextarea.value = tmpMdwintJSON;\n\n\t\t// Build the mdwint CLI command\n\t\tlet tmpMdwintCLI = 'mdwint clone --schema_path ./schema/Model-Extended.json';\n\t\tlet tmpMdwintCLIDiv = document.getElementById('mdwintCLICommand');\n\t\ttmpMdwintCLIDiv.querySelector('div').textContent = tmpMdwintCLI;\n\n\t\t// Provider compatibility note\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tif (tmpProvider !== 'MySQL' && tmpProvider !== 'MSSQL')\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Note: mdwint clone only supports MySQL and MSSQL destinations. The config defaults to MySQL; update the Destination section for your target database.', 'warn');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', '', '');\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Config generated. Save as clone-config.json or copy the one-liner below.', 'ok');\n\t}\n\n\tcopyConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Generate a config first.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpTextarea.value).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'Config copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyCLI()\n\t{\n\t\tlet tmpCmd = document.getElementById('cliCommand').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'CLI command copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyOneShot()\n\t{\n\t\tlet tmpCmd = document.getElementById('cliOneShot').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'One-liner copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tdownloadConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.generateConfig();\n\t\t}\n\t\tlet tmpBlob = new Blob([tmpTextarea.value], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\ttmpAnchor.download = 'clone-config.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Config downloaded as clone-config.json.', 'ok');\n\t}\n\n\tcopyMdwintConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('mdwintConfigOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Generate a config first.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpTextarea.value).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('mdwintConfigStatus', '.meadow.config.json copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyMdwintCLI()\n\t{\n\t\tlet tmpCmd = document.getElementById('mdwintCLICommand').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'mdwint CLI command copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tdownloadMdwintConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('mdwintConfigOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.generateConfig();\n\t\t}\n\t\tlet tmpBlob = new Blob([tmpTextarea.value], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\ttmpAnchor.download = '.meadow.config.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Config downloaded as .meadow.config.json.', 'ok');\n\t}\n}\n\nmodule.exports = DataClonerExportView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Export',\n\tDefaultRenderable: 'DataCloner-Export',\n\tDefaultDestinationAddress: '#DataCloner-Section-Export',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Export',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">6</div>\n\t<div class=\"accordion-card\" id=\"section6\" data-section=\"6\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section6')\">\n\t\t\t<div class=\"accordion-title\">Export Configuration</div>\n\t\t\t<div class=\"accordion-preview\" id=\"preview6\">Generate JSON config for headless cloning</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Generate a JSON config file from your current settings. Use it to run headless clones from the command line.</p>\n\t\t\t<div style=\"display:flex; gap:8px; margin-bottom:10px\">\n\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Export'].generateConfig()\">Generate Config</button>\n\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].copyConfig()\">Copy to Clipboard</button>\n\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].downloadConfig()\">Download JSON</button>\n\t\t\t</div>\n\t\t\t<div id=\"configExportStatus\"></div>\n\t\t\t<div id=\"cliCommand\" style=\"display:none; margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:4px\">CLI Command <span style=\"color:#888; font-weight:normal\">(with config file)</span></label>\n\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer\" onclick=\"pict.views['DataCloner-Export'].copyCLI()\" title=\"Click to copy\"></div>\n\t\t\t</div>\n\t\t\t<div id=\"cliOneShot\" style=\"display:none; margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:4px\">One-liner <span style=\"color:#888; font-weight:normal\">(no config file needed)</span></label>\n\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer; white-space:pre-wrap\" onclick=\"pict.views['DataCloner-Export'].copyOneShot()\" title=\"Click to copy\"></div>\n\t\t\t</div>\n\t\t\t<textarea id=\"configOutput\" style=\"display:none; width:100%; min-height:300px; font-family:monospace; font-size:0.85em; padding:10px; border:1px solid #ccc; border-radius:4px; background:#fafafa; tab-size:4; resize:vertical\" readonly></textarea>\n\n\t\t\t<div id=\"mdwintExport\" style=\"display:none; margin-top:16px; padding-top:16px; border-top:1px solid #eee\">\n\t\t\t\t<h3 style=\"margin:0 0 8px; font-size:1em\">meadow-integration CLI <span style=\"color:#888; font-weight:normal; font-size:0.85em\">(mdwint clone)</span></h3>\n\t\t\t\t<p style=\"font-size:0.85em; color:#666; margin-bottom:8px\">Save as <code>.meadow.config.json</code> in your project root, then run the command below. Requires a local Meadow extended schema JSON file.</p>\n\t\t\t\t<div style=\"display:flex; gap:8px; margin-bottom:10px\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].copyMdwintConfig()\">Copy Config</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].downloadMdwintConfig()\">Download .meadow.config.json</button>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"mdwintCLICommand\" style=\"margin-bottom:10px\">\n\t\t\t\t\t<label style=\"margin-bottom:4px\">CLI Command</label>\n\t\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer\" onclick=\"pict.views['DataCloner-Export'].copyMdwintCLI()\" title=\"Click to copy\"></div>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"mdwintConfigStatus\"></div>\n\t\t\t\t<textarea id=\"mdwintConfigOutput\" style=\"width:100%; min-height:250px; font-family:monospace; font-size:0.85em; padding:10px; border:1px solid #ccc; border-radius:4px; background:#fafafa; tab-size:4; resize:vertical\" readonly></textarea>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Export',\n\t\t\tTemplateHash: 'DataCloner-Export',\n\t\t\tDestinationAddress: '#DataCloner-Section-Export'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],22:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerLayoutView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tonAfterRender()\n\t{\n\t\t// Render all section views into their containers\n\t\tthis.pict.views['DataCloner-Connection'].render();\n\t\tthis.pict.views['DataCloner-Session'].render();\n\t\tthis.pict.views['DataCloner-Schema'].render();\n\t\tthis.pict.views['DataCloner-Deploy'].render();\n\t\tthis.pict.views['DataCloner-Sync'].render();\n\t\tthis.pict.views['DataCloner-Export'].render();\n\t\tthis.pict.views['DataCloner-ViewData'].render();\n\n\t\tthis.pict.CSSMap.injectCSS();\n\t}\n\n\ttoggleSection(pSectionId)\n\t{\n\t\tlet tmpCard = document.getElementById(pSectionId);\n\t\tif (!tmpCard) return;\n\t\ttmpCard.classList.toggle('open');\n\t}\n\n\texpandAllSections()\n\t{\n\t\tlet tmpCards = document.querySelectorAll('.accordion-card');\n\t\tfor (let i = 0; i < tmpCards.length; i++)\n\t\t{\n\t\t\ttmpCards[i].classList.add('open');\n\t\t}\n\t}\n\n\tcollapseAllSections()\n\t{\n\t\tlet tmpCards = document.querySelectorAll('.accordion-card');\n\t\tfor (let i = 0; i < tmpCards.length; i++)\n\t\t{\n\t\t\ttmpCards[i].classList.remove('open');\n\t\t}\n\t}\n\n\ttoggleStatusDetail()\n\t{\n\t\tlet tmpDetail = document.getElementById('liveStatusDetail');\n\t\tlet tmpMeta = document.getElementById('liveStatusMeta');\n\t\tlet tmpMessage = document.getElementById('liveStatusMessage');\n\t\tlet tmpToggle = document.getElementById('liveStatusToggle');\n\t\tlet tmpBar = document.getElementById('liveStatusBar');\n\t\tif (!tmpDetail) return;\n\n\t\tlet tmpIsExpanded = tmpDetail.style.display !== 'none';\n\n\t\tif (tmpIsExpanded)\n\t\t{\n\t\t\ttmpDetail.style.display = 'none';\n\t\t\ttmpMeta.style.display = '';\n\t\t\ttmpMessage.style.display = '';\n\t\t\ttmpToggle.innerHTML = '▼';\n\t\t\ttmpBar.classList.remove('expanded');\n\t\t\tthis.pict.providers.DataCloner.onStatusDetailCollapsed();\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpDetail.style.display = '';\n\t\t\ttmpMeta.style.display = 'none';\n\t\t\ttmpMessage.style.display = 'none';\n\t\t\ttmpToggle.innerHTML = '▲';\n\t\t\ttmpBar.classList.add('expanded');\n\t\t\tthis.pict.providers.DataCloner.onStatusDetailExpanded();\n\t\t}\n\t}\n}\n\nmodule.exports = DataClonerLayoutView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Layout',\n\tDefaultRenderable: 'DataCloner-Layout',\n\tDefaultDestinationAddress: '#DataCloner-Application-Container',\n\tCSS: /*css*/`\n* { box-sizing: border-box; margin: 0; padding: 0; }\nbody { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; color: #333; padding: 20px; }\nh1 { margin-bottom: 20px; color: #1a1a1a; }\nh2 { margin-bottom: 12px; color: #444; font-size: 1.2em; border-bottom: 2px solid #ddd; padding-bottom: 6px; }\n\n.section { background: #fff; border-radius: 8px; padding: 20px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n\n/* Accordion layout */\n.accordion-row { display: flex; gap: 0; margin-bottom: 16px; align-items: stretch; }\n.accordion-number {\n\tflex: 0 0 48px; display: flex; align-items: flex-start; justify-content: center;\n\tpadding-top: 16px; font-size: 1.6em; font-weight: 700; color: #4a90d9;\n\tuser-select: none;\n}\n.accordion-card {\n\tflex: 1; background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n\toverflow: hidden; min-width: 0;\n}\n.accordion-header {\n\tdisplay: flex; align-items: center; padding: 14px 20px; cursor: pointer;\n\tuser-select: none; gap: 12px; transition: background 0.15s; line-height: 1.4;\n}\n.accordion-header:hover { background: #fafafa; }\n.accordion-title { font-weight: 600; color: #333; font-size: 1.05em; white-space: nowrap; }\n.accordion-preview { flex: 1; font-style: italic; color: #888; font-size: 0.9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }\n.accordion-toggle {\n\tflex: 0 0 20px; display: flex; align-items: center; justify-content: center;\n\tborder-radius: 4px; transition: background 0.15s, transform 0.25s; font-size: 0.7em; color: #888;\n}\n.accordion-header:hover .accordion-toggle { background: #eee; color: #555; }\n.accordion-card.open .accordion-toggle { transform: rotate(180deg); }\n.accordion-body { padding: 0 20px 20px; display: none; }\n.accordion-card.open .accordion-body { display: block; }\n.accordion-card.open .accordion-header { border-bottom: 1px solid #eee; }\n.accordion-card.open .accordion-preview { display: none; }\n\n/* Action controls (go link + auto checkbox) */\n.accordion-actions { display: flex; align-items: baseline; gap: 8px; flex-shrink: 0; }\n.accordion-card.open .accordion-actions { display: none; }\n.accordion-go {\n\tfont-size: 0.82em; color: #4a90d9; cursor: pointer; text-decoration: none;\n\tfont-weight: 500; white-space: nowrap; padding: 2px 6px; border-radius: 3px;\n\ttransition: background 0.15s;\n}\n.accordion-go:hover { background: #e8f0fe; text-decoration: underline; }\n.accordion-auto {\n\tfont-size: 0.82em; color: #999; white-space: nowrap; cursor: pointer;\n}\n.accordion-auto .auto-label { display: none; }\n.accordion-auto:hover .auto-label { display: inline; }\n.accordion-auto input[type=\"checkbox\"] { width: auto; margin: 0; cursor: pointer; vertical-align: middle; position: relative; top: 0px; opacity: 0.75; transition: opacity 0.15s; }\n.accordion-auto:hover input[type=\"checkbox\"] { opacity: 1; }\n.accordion-auto:hover { color: #666; }\n\n/* Phase status indicator */\n.accordion-phase {\n\tflex: 0 0 auto; display: none; align-items: center; justify-content: center;\n\tfont-size: 0.85em; line-height: 1;\n}\n.accordion-phase.visible { display: flex; }\n.accordion-phase-ok { color: #28a745; }\n.accordion-phase-error { color: #dc3545; }\n.accordion-phase-busy { color: #28a745; }\n.accordion-phase-busy .phase-spinner {\n\tdisplay: inline-block; width: 14px; height: 14px;\n\tborder: 2px solid #28a745; border-top-color: transparent; border-radius: 50%;\n\tanimation: phase-spin 0.8s linear infinite; vertical-align: middle;\n}\n@keyframes phase-spin {\n\tto { transform: rotate(360deg); }\n}\n\n.accordion-controls {\n\tdisplay: flex; gap: 8px; margin-bottom: 12px; justify-content: flex-end;\n}\n.accordion-controls button {\n\tpadding: 4px 10px; font-size: 0.82em; font-weight: 500; background: none;\n\tborder: 1px solid #ccc; border-radius: 4px; color: #666; cursor: pointer; margin: 0;\n}\n.accordion-controls button:hover { background: #f0f0f0; border-color: #aaa; color: #333; }\n\nlabel { display: block; font-weight: 600; margin-bottom: 4px; font-size: 0.9em; }\ninput[type=\"text\"], input[type=\"password\"], input[type=\"number\"] {\n\twidth: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px;\n\tfont-size: 0.95em; margin-bottom: 10px;\n}\ninput[type=\"text\"]:focus, input[type=\"password\"]:focus, input[type=\"number\"]:focus {\n\toutline: none; border-color: #4a90d9;\n}\n\nbutton {\n\tpadding: 8px 16px; border: none; border-radius: 4px; cursor: pointer;\n\tfont-size: 0.9em; font-weight: 600; margin-right: 8px; margin-bottom: 8px;\n}\nbutton.primary { background: #4a90d9; color: #fff; }\nbutton.primary:hover { background: #357abd; }\nbutton.secondary { background: #6c757d; color: #fff; }\nbutton.secondary:hover { background: #5a6268; }\nbutton.danger { background: #dc3545; color: #fff; }\nbutton.danger:hover { background: #c82333; }\nbutton.success { background: #28a745; color: #fff; }\nbutton.success:hover { background: #218838; }\nbutton:disabled { opacity: 0.5; cursor: not-allowed; }\n\n.status { padding: 8px 12px; border-radius: 4px; margin-top: 10px; font-size: 0.9em; }\n.status.ok { background: #d4edda; color: #155724; }\n.status.error { background: #f8d7da; color: #721c24; }\n.status.info { background: #d1ecf1; color: #0c5460; }\n.status.warn { background: #fff3cd; color: #856404; }\n\n.inline-group { display: flex; gap: 8px; align-items: flex-end; margin-bottom: 10px; }\n.inline-group > div { flex: 1; }\n\na { color: #4a90d9; }\n\nselect { background: #fff; width: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 0.95em; margin-bottom: 10px; }\n\n.checkbox-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }\n.checkbox-row input[type=\"checkbox\"] { width: auto; margin: 0; }\n.checkbox-row label { display: inline; margin: 0; font-weight: normal; cursor: pointer; }\n\n/* Live Status Bar */\n.live-status-bar {\n\tbackground: #fff; border-radius: 8px; margin-bottom: 16px;\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.1);\n\tposition: sticky; top: 0; z-index: 100; border-left: 4px solid #6c757d;\n}\n.live-status-bar.phase-idle { border-left-color: #6c757d; }\n.live-status-bar.phase-disconnected { border-left-color: #dc3545; }\n.live-status-bar.phase-ready { border-left-color: #4a90d9; }\n.live-status-bar.phase-syncing { border-left-color: #28a745; }\n.live-status-bar.phase-stopping { border-left-color: #ffc107; }\n.live-status-bar.phase-complete { border-left-color: #28a745; }\n\n.live-status-dot {\n\twidth: 12px; height: 12px; border-radius: 50%; flex-shrink: 0;\n\tbackground: #6c757d;\n}\n.live-status-bar.phase-idle .live-status-dot { background: #6c757d; }\n.live-status-bar.phase-disconnected .live-status-dot { background: #dc3545; }\n.live-status-bar.phase-ready .live-status-dot { background: #4a90d9; }\n.live-status-bar.phase-syncing .live-status-dot {\n\tbackground: #28a745;\n\tanimation: live-pulse 1.5s ease-in-out infinite;\n}\n.live-status-bar.phase-stopping .live-status-dot {\n\tbackground: #ffc107;\n\tanimation: live-pulse 0.8s ease-in-out infinite;\n}\n.live-status-bar.phase-complete .live-status-dot { background: #28a745; }\n\n@keyframes live-pulse {\n\t0%, 100% { opacity: 1; transform: scale(1); }\n\t50% { opacity: 0.4; transform: scale(0.8); }\n}\n\n.live-status-message { flex: 1; font-size: 0.92em; color: #333; line-height: 1.4; }\n\n.live-status-meta {\n\tdisplay: flex; gap: 16px; flex-shrink: 0; font-size: 0.82em; color: #666;\n}\n.live-status-meta-item { white-space: nowrap; }\n.live-status-meta-item strong { color: #333; }\n\n.live-status-progress-bar {\n\theight: 3px; background: #e9ecef; border-radius: 2px; overflow: hidden;\n\tposition: absolute; bottom: 0; left: 0; right: 0;\n}\n.live-status-progress-fill {\n\theight: 100%; background: #28a745; transition: width 1s ease;\n}\n/* Expandable status bar */\n.live-status-header {\n\tdisplay: flex; align-items: center; gap: 14px; cursor: pointer;\n\tpadding: 14px 20px; user-select: none;\n}\n.live-status-bar.expanded .live-status-header {\n\tborder-bottom: 1px solid #e9ecef; padding-bottom: 10px;\n}\n.live-status-expand-toggle {\n\tflex: 0 0 20px; display: flex; align-items: center; justify-content: center;\n\tfont-size: 0.7em; color: #888; transition: transform 0.25s;\n}\n.live-status-bar.expanded .live-status-expand-toggle { transform: rotate(180deg); }\n\n.live-status-detail {\n\tpadding: 12px 20px 16px; max-height: 60vh; overflow-y: auto;\n}\n\n/* Status Detail Summary Banner */\n.status-detail-summary {\n\tdisplay: flex; align-items: center; gap: 16px; flex-wrap: wrap;\n\tpadding: 8px 0 12px; margin-bottom: 12px; border-bottom: 1px solid #e9ecef;\n}\n.status-detail-summary-message {\n\tfont-size: 0.92em; color: #333; font-weight: 600;\n}\n.status-detail-summary-counters {\n\tdisplay: flex; gap: 16px; flex-wrap: wrap; font-size: 0.82em; color: #666;\n}\n\n/* Status Detail Sections */\n.status-detail-section { margin-bottom: 14px; }\n.status-detail-section:last-child { margin-bottom: 0; }\n.status-detail-section-title {\n\tfont-size: 0.85em; font-weight: 600; color: #555; text-transform: uppercase;\n\tletter-spacing: 0.5px; margin-bottom: 8px; padding-bottom: 4px;\n\tborder-bottom: 1px solid #eee;\n}\n\n/* Running Operations */\n.running-op-row {\n\tdisplay: flex; align-items: center; gap: 12px; padding: 6px 0;\n\tfont-size: 0.9em;\n}\n.running-op-name { font-weight: 600; min-width: 180px; }\n.running-op-bar {\n\tflex: 1; height: 8px; background: #e9ecef; border-radius: 4px; overflow: hidden;\n\tmin-width: 120px;\n}\n.running-op-bar-fill { height: 100%; background: #4a90d9; transition: width 0.5s ease; }\n.running-op-count { font-size: 0.85em; color: #666; white-space: nowrap; }\n.running-op-pending { color: #888; font-size: 0.85em; font-style: italic; padding: 4px 0; }\n\n/* Completed Operations */\n.completed-op-row { padding: 8px 0; border-bottom: 1px solid #f0f0f0; }\n.completed-op-row:last-child { border-bottom: none; }\n.completed-op-header {\n\tdisplay: flex; align-items: center; gap: 10px; font-size: 0.9em; margin-bottom: 4px;\n}\n.completed-op-name { font-weight: 600; }\n.completed-op-stats { color: #666; font-size: 0.85em; }\n.completed-op-checkmark { color: #28a745; }\n\n/* Ratio Bar */\n.ratio-bar-container {\n\tdisplay: flex; height: 10px; border-radius: 5px; overflow: hidden;\n\tbackground: #e9ecef; margin: 4px 0;\n}\n.ratio-bar-segment { height: 100%; transition: width 0.5s ease; }\n.ratio-bar-segment.unchanged { background: #6c757d; }\n.ratio-bar-segment.new-records { background: #28a745; }\n.ratio-bar-segment.updated { background: #4a90d9; }\n.ratio-bar-segment.deleted { background: #dc3545; }\n.ratio-bar-legend {\n\tdisplay: flex; gap: 12px; font-size: 0.75em; color: #666; margin-top: 2px; flex-wrap: wrap;\n}\n.ratio-bar-legend-item { display: flex; align-items: center; gap: 4px; }\n.ratio-bar-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }\n.ratio-bar-legend-dot.unchanged-dot { background: #6c757d; }\n.ratio-bar-legend-dot.new-dot { background: #28a745; }\n.ratio-bar-legend-dot.updated-dot { background: #4a90d9; }\n.ratio-bar-legend-dot.deleted-dot { background: #dc3545; }\n\n/* Error Operations */\n.error-op-row { padding: 6px 0; border-bottom: 1px solid #f0f0f0; font-size: 0.9em; }\n.error-op-row:last-child { border-bottom: none; }\n.error-op-header { display: flex; align-items: center; gap: 8px; }\n.error-op-name { font-weight: 600; color: #dc3545; }\n.error-op-status { font-size: 0.82em; color: #dc3545; }\n.error-op-message { font-size: 0.82em; color: #888; margin-top: 2px; padding-left: 18px; }\n.error-op-log-entries {\n\tfont-size: 0.78em; color: #888; margin-top: 4px; padding-left: 18px;\n\tfont-family: monospace; max-height: 80px; overflow-y: auto;\n}\n\n/* Pre-count Table */\n.precount-table {\n\twidth: 100%; border-collapse: collapse; font-size: 0.88em;\n}\n.precount-table thead th {\n\ttext-align: left; font-weight: 600; color: #555; font-size: 0.85em;\n\ttext-transform: uppercase; letter-spacing: 0.3px;\n\tpadding: 4px 8px 6px; border-bottom: 2px solid #e9ecef;\n}\n.precount-table tbody td {\n\tpadding: 4px 8px; border-bottom: 1px solid #f0f0f0;\n}\n.precount-table tbody tr:last-child td { border-bottom: 1px solid #e9ecef; }\n.precount-table tfoot td {\n\tpadding: 6px 8px 2px; font-size: 0.95em;\n}\n.precount-error td { color: #dc3545; }\n.precount-pending {\n\tcolor: #888; font-size: 0.85em; font-style: italic; padding: 8px 0 2px;\n\tdisplay: flex; align-items: center; gap: 6px;\n}\n.precount-spinner {\n\tdisplay: inline-block; width: 12px; height: 12px;\n\tborder: 2px solid #ddd; border-top-color: #4a90d9;\n\tborder-radius: 50%; animation: precount-spin 0.8s linear infinite;\n}\n@keyframes precount-spin { to { transform: rotate(360deg); } }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Layout',\n\t\t\tTemplate: /*html*/`\n<h1>Retold Data Cloner</h1>\n\n<!-- Live Status Bar (Expandable) -->\n<div id=\"liveStatusBar\" class=\"live-status-bar phase-idle\" style=\"position:relative\">\n\t<div class=\"live-status-header\" onclick=\"pict.views['DataCloner-Layout'].toggleStatusDetail()\">\n\t\t<div class=\"live-status-dot\"></div>\n\t\t<div class=\"live-status-message\" id=\"liveStatusMessage\">Idle</div>\n\t\t<div class=\"live-status-meta\" id=\"liveStatusMeta\"></div>\n\t\t<div class=\"live-status-expand-toggle\" id=\"liveStatusToggle\">▼</div>\n\t</div>\n\t<div class=\"live-status-detail\" id=\"liveStatusDetail\" style=\"display:none\">\n\t\t<div id=\"DataCloner-Throughput-Histogram\"></div>\n\t\t<div id=\"DataCloner-StatusDetail-Container\"></div>\n\t</div>\n\t<div class=\"live-status-progress-bar\"><div class=\"live-status-progress-fill\" id=\"liveStatusProgressFill\" style=\"width:0%\"></div></div>\n</div>\n\n<!-- Expand / Collapse All -->\n<div class=\"accordion-controls\">\n\t<button onclick=\"pict.views['DataCloner-Layout'].expandAllSections()\">Expand All</button>\n\t<button onclick=\"pict.views['DataCloner-Layout'].collapseAllSections()\">Collapse All</button>\n</div>\n\n<!-- Section containers -->\n<div id=\"DataCloner-Section-Connection\"></div>\n<div id=\"DataCloner-Section-Session\"></div>\n<div id=\"DataCloner-Section-Schema\"></div>\n<div id=\"DataCloner-Section-Deploy\"></div>\n<div id=\"DataCloner-Section-Sync\"></div>\n<div id=\"DataCloner-Section-Export\"></div>\n<div id=\"DataCloner-Section-ViewData\"></div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Layout',\n\t\t\tTemplateHash: 'DataCloner-Layout',\n\t\t\tDestinationAddress: '#DataCloner-Application-Container'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],23:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerSchemaView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tfetchSchema()\n\t{\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tlet tmpBody = {};\n\t\tif (tmpSchemaURL)\n\t\t{\n\t\t\ttmpBody.SchemaURL = tmpSchemaURL;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetching schema...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/fetch', tmpBody)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.AppData.DataCloner.FetchedTables = pData.Tables || [];\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetched ' + pData.TableCount + ' tables from ' + pData.SchemaURL, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'ok');\n\t\t\t\t\t\tthis.renderTableList();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetch failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'error');\n\t\t\t\t});\n\t}\n\n\tloadSavedSelections()\n\t{\n\t\ttry\n\t\t{\n\t\t\tlet tmpRaw = localStorage.getItem('dataCloner_selectedTables');\n\t\t\tif (tmpRaw)\n\t\t\t{\n\t\t\t\treturn JSON.parse(tmpRaw);\n\t\t\t}\n\t\t}\n\t\tcatch (pError)\n\t\t{\n\t\t\t/* ignore */\n\t\t}\n\t\treturn null;\n\t}\n\n\tsaveSelections()\n\t{\n\t\tlet tmpSelected = this.getSelectedTables();\n\t\tlocalStorage.setItem('dataCloner_selectedTables', JSON.stringify(tmpSelected));\n\t\tthis.updateSelectionCount();\n\t\tthis.pict.providers.DataCloner.updateAllPreviews();\n\t}\n\n\tupdateSelectionCount()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpCount = this.getSelectedTables().length;\n\t\tlet tmpEl = document.getElementById('tableSelectionCount');\n\t\tif (tmpEl)\n\t\t{\n\t\t\ttmpEl.textContent = tmpCount + ' / ' + tmpFetchedTables.length + ' selected';\n\t\t}\n\t}\n\n\trenderTableList()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpContainer = document.getElementById('tableList');\n\t\ttmpContainer.innerHTML = '';\n\n\t\t// Load previously saved selections; if none, default to none checked\n\t\tlet tmpSaved = this.loadSavedSelections();\n\t\tlet tmpSavedSet = null;\n\t\tif (tmpSaved)\n\t\t{\n\t\t\ttmpSavedSet = {};\n\t\t\tfor (let i = 0; i < tmpSaved.length; i++)\n\t\t\t{\n\t\t\t\ttmpSavedSet[tmpSaved[i]] = true;\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpFetchedTables[i];\n\t\t\tlet tmpDiv = document.createElement('div');\n\t\t\ttmpDiv.className = 'table-item';\n\t\t\ttmpDiv.setAttribute('data-table', tmpName.toLowerCase());\n\n\t\t\tlet tmpCheckbox = document.createElement('input');\n\t\t\ttmpCheckbox.type = 'checkbox';\n\t\t\ttmpCheckbox.id = 'tbl_' + tmpName;\n\t\t\ttmpCheckbox.value = tmpName;\n\t\t\t// If we have saved selections, restore them; otherwise default unchecked\n\t\t\ttmpCheckbox.checked = tmpSavedSet ? (tmpSavedSet[tmpName] === true) : false;\n\t\t\ttmpCheckbox.addEventListener('change', () => { this.saveSelections(); });\n\n\t\t\tlet tmpLabel = document.createElement('label');\n\t\t\ttmpLabel.htmlFor = 'tbl_' + tmpName;\n\t\t\ttmpLabel.textContent = tmpName;\n\n\t\t\ttmpDiv.appendChild(tmpCheckbox);\n\t\t\ttmpDiv.appendChild(tmpLabel);\n\t\t\ttmpContainer.appendChild(tmpDiv);\n\t\t}\n\n\t\tdocument.getElementById('tableSelection').style.display = tmpFetchedTables.length > 0 ? 'block' : 'none';\n\t\tdocument.getElementById('tableFilter').value = '';\n\t\tthis.updateSelectionCount();\n\t}\n\n\tfilterTableList()\n\t{\n\t\tlet tmpFilter = document.getElementById('tableFilter').value.toLowerCase().trim();\n\t\tlet tmpItems = document.getElementById('tableList').children;\n\t\tfor (let i = 0; i < tmpItems.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpItems[i].getAttribute('data-table') || '';\n\t\t\ttmpItems[i].style.display = (!tmpFilter || tmpName.indexOf(tmpFilter) >= 0) ? '' : 'none';\n\t\t}\n\t}\n\n\tselectAllTables(pChecked)\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\t// Only affect visible (non-filtered) items\n\t\tlet tmpFilter = document.getElementById('tableFilter').value.toLowerCase().trim();\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpFetchedTables[i];\n\t\t\tif (tmpFilter && tmpName.toLowerCase().indexOf(tmpFilter) < 0)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet tmpCheckbox = document.getElementById('tbl_' + tmpName);\n\t\t\tif (tmpCheckbox)\n\t\t\t{\n\t\t\t\ttmpCheckbox.checked = pChecked;\n\t\t\t}\n\t\t}\n\t\tthis.saveSelections();\n\t}\n\n\tgetSelectedTables()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpSelected = [];\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpCheckbox = document.getElementById('tbl_' + tmpFetchedTables[i]);\n\t\t\tif (tmpCheckbox && tmpCheckbox.checked)\n\t\t\t{\n\t\t\t\ttmpSelected.push(tmpFetchedTables[i]);\n\t\t\t}\n\t\t}\n\t\treturn tmpSelected;\n\t}\n}\n\nmodule.exports = DataClonerSchemaView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Schema',\n\tDefaultRenderable: 'DataCloner-Schema',\n\tDefaultDestinationAddress: '#DataCloner-Section-Schema',\n\tCSS: /*css*/`\n.table-list { max-height: 300px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 8px; margin: 10px 0; }\n.table-item { padding: 4px 8px; display: flex; align-items: center; }\n.table-item:hover { background: #f0f0f0; }\n.table-item input[type=\"checkbox\"] { margin-right: 8px; width: auto; }\n.table-item label { display: inline; font-weight: normal; margin-bottom: 0; cursor: pointer; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Schema',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">3</div>\n\t<div class=\"accordion-card\" id=\"section3\" data-section=\"3\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section3')\">\n\t\t\t<div class=\"accordion-title\">Remote Schema</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase3\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview3\">Fetch and select tables from the remote server</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Schema'].fetchSchema()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto3\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<label for=\"schemaURL\">Schema URL (leave blank for default: /1.0/Retold/Models)</label>\n\t\t\t<input type=\"text\" id=\"schemaURL\" placeholder=\"http://remote-server:8086/1.0/Retold/Models\">\n\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Schema'].fetchSchema()\">Fetch Schema</button>\n\t\t\t<div id=\"schemaStatus\"></div>\n\n\t\t\t<div id=\"tableSelection\" style=\"display:none\">\n\t\t\t\t<h3 style=\"margin:12px 0 8px; font-size:1em;\">Select Tables</h3>\n\t\t\t\t<div style=\"display:flex; gap:8px; align-items:center; margin-bottom:8px\">\n\t\t\t\t\t<input type=\"text\" id=\"tableFilter\" placeholder=\"Filter tables...\" style=\"flex:1; margin-bottom:0\" oninput=\"pict.views['DataCloner-Schema'].filterTableList()\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Schema'].selectAllTables(true)\" style=\"font-size:0.8em\">Select All</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Schema'].selectAllTables(false)\" style=\"font-size:0.8em\">Deselect All</button>\n\t\t\t\t\t<span id=\"tableSelectionCount\" style=\"font-size:0.85em; color:#666; white-space:nowrap\"></span>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"tableList\" class=\"table-list\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Schema',\n\t\t\tTemplateHash: 'DataCloner-Schema',\n\t\t\tDestinationAddress: '#DataCloner-Section-Schema'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],24:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerSessionView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tconfigureSession()\n\t{\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\tif (!tmpServerURL)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Server URL is required.', 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBody = { ServerURL: tmpServerURL.replace(/\\/+$/, '') + '/1.0/' };\n\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim();\n\t\tif (tmpAuthMethod)\n\t\t{\n\t\t\ttmpBody.AuthenticationMethod = tmpAuthMethod;\n\t\t}\n\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI)\n\t\t{\n\t\t\ttmpBody.AuthenticationURITemplate = tmpAuthURI;\n\t\t}\n\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI)\n\t\t{\n\t\t\ttmpBody.CheckSessionURITemplate = tmpCheckURI;\n\t\t}\n\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\tif (tmpCookieName)\n\t\t{\n\t\t\ttmpBody.CookieName = tmpCookieName;\n\t\t}\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr)\n\t\t{\n\t\t\ttmpBody.CookieValueAddress = tmpCookieValueAddr;\n\t\t}\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate)\n\t\t{\n\t\t\ttmpBody.CookieValueTemplate = tmpCookieValueTemplate;\n\t\t}\n\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\tif (tmpLoginMarker)\n\t\t{\n\t\t\ttmpBody.CheckSessionLoginMarker = tmpLoginMarker;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Configuring session...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/configure', tmpBody)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Session configured for ' + pData.ServerURL + ' (domain: ' + pData.DomainMatch + ')', 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Configuration failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tauthenticate()\n\t{\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value.trim();\n\n\t\tif (!tmpUserName || !tmpPassword)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Username and password are required.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authenticating...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/authenticate', { UserName: tmpUserName, Password: tmpPassword })\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success && pData.Authenticated)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authenticated successfully.', 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authentication failed: ' + (pData.Error || 'Not authenticated'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\t\t});\n\t}\n\n\tcheckSession()\n\t{\n\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Checking session...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/session/check')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Authenticated)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session is active. Server: ' + (pData.ServerURL || 'N/A'), 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse if (pData.Configured)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session configured but not authenticated.', 'warn');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'No session configured.', 'warn');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tdeauthenticate()\n\t{\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/deauthenticate')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session deauthenticated.', 'info');\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tgoAction()\n\t{\n\t\t// Two-step: configure session, then authenticate after delay\n\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'busy');\n\t\tthis.configureSession();\n\t\tsetTimeout(\n\t\t\t() =>\n\t\t\t{\n\t\t\t\tthis.authenticate();\n\t\t\t}, 1500);\n\t}\n}\n\nmodule.exports = DataClonerSessionView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Session',\n\tDefaultRenderable: 'DataCloner-Session',\n\tDefaultDestinationAddress: '#DataCloner-Section-Session',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Session',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">2</div>\n\t<div class=\"accordion-card\" id=\"section2\" data-section=\"2\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section2')\">\n\t\t\t<div class=\"accordion-title\">Remote Session</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase2\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview2\">Configure remote server URL and credentials</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Session'].goAction()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto2\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t<label for=\"serverURL\">Remote Server URL</label>\n\t\t\t\t\t<input type=\"text\" id=\"serverURL\" placeholder=\"http://remote-server:8086\" value=\"\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t<label for=\"authMethod\">Auth Method</label>\n\t\t\t\t\t<input type=\"text\" id=\"authMethod\" placeholder=\"get\" value=\"get\">\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<details style=\"margin-bottom:10px\">\n\t\t\t\t<summary style=\"cursor:pointer; font-size:0.9em; color:#666\">Advanced Session Options</summary>\n\t\t\t\t<div style=\"padding:10px 0\">\n\t\t\t\t\t<label for=\"authURI\">Authentication URI Template (leave blank for default)</label>\n\t\t\t\t\t<input type=\"text\" id=\"authURI\" placeholder=\"Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}\">\n\t\t\t\t\t<label for=\"checkURI\">Check Session URI Template</label>\n\t\t\t\t\t<input type=\"text\" id=\"checkURI\" placeholder=\"CheckSession\">\n\t\t\t\t\t<label for=\"cookieName\">Cookie Name</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieName\" placeholder=\"SessionID\" value=\"SessionID\">\n\t\t\t\t\t<label for=\"cookieValueAddr\">Cookie Value Address</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieValueAddr\" placeholder=\"SessionID\" value=\"SessionID\">\n\t\t\t\t\t<label for=\"cookieValueTemplate\">Cookie Value Template (overrides Address if set)</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieValueTemplate\" placeholder=\"{~D:Record.SessionID~}\">\n\t\t\t\t\t<label for=\"loginMarker\">Login Marker</label>\n\t\t\t\t\t<input type=\"text\" id=\"loginMarker\" placeholder=\"LoggedIn\" value=\"LoggedIn\">\n\t\t\t\t</div>\n\t\t\t</details>\n\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Session'].configureSession()\">Configure Session</button>\n\t\t\t<div id=\"sessionConfigStatus\"></div>\n\n\t\t\t<hr style=\"margin:16px 0; border:none; border-top:1px solid #eee\">\n\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div>\n\t\t\t\t\t<label for=\"userName\">Username</label>\n\t\t\t\t\t<input type=\"text\" id=\"userName\" placeholder=\"username\">\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<label for=\"password\">Password</label>\n\t\t\t\t\t<input type=\"password\" id=\"password\" placeholder=\"password\">\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<button class=\"success\" onclick=\"pict.views['DataCloner-Session'].authenticate()\">Authenticate</button>\n\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Session'].checkSession()\">Check Session</button>\n\t\t\t<button class=\"danger\" onclick=\"pict.views['DataCloner-Session'].deauthenticate()\">Deauthenticate</button>\n\t\t\t<div id=\"sessionAuthStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Session',\n\t\t\tTemplateHash: 'DataCloner-Session',\n\t\t\tDestinationAddress: '#DataCloner-Section-Session'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],25:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerSyncView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tstartSync()\n\t{\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\tlet tmpPageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\tlet tmpDateTimePrecisionMS = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (isNaN(tmpDateTimePrecisionMS)) tmpDateTimePrecisionMS = 1000;\n\t\tlet tmpSyncDeletedRecords = document.getElementById('syncDeletedRecords').checked;\n\t\tlet tmpSyncMode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\tlet tmpMaxRecords = parseInt(document.getElementById('syncMaxRecords').value, 10) || 0;\n\t\tlet tmpLogToFile = document.getElementById('syncLogFile').checked;\n\t\tlet tmpAdvancedIDPagination = document.getElementById('syncAdvancedIDPagination').checked;\n\n\t\tif (tmpSelectedTables.length === 0)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('syncStatus', 'No tables selected for sync.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(5, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('syncStatus', 'Starting ' + tmpSyncMode.toLowerCase() + ' sync...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tlet tmpPostBody = { Tables: tmpSelectedTables, PageSize: tmpPageSize, DateTimePrecisionMS: tmpDateTimePrecisionMS, SyncDeletedRecords: tmpSyncDeletedRecords, SyncMode: tmpSyncMode };\n\t\tif (tmpMaxRecords > 0) tmpPostBody.MaxRecordsPerEntity = tmpMaxRecords;\n\t\tif (tmpLogToFile) tmpPostBody.LogToFile = true;\n\t\tif (tmpAdvancedIDPagination) tmpPostBody.UseAdvancedIDPagination = true;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/sync/start', tmpPostBody)\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\tlet tmpMsg = pData.SyncMode + ' sync started for ' + pData.Tables.length + ' tables.';\n\t\t\t\t\tif (pData.SyncDeletedRecords) tmpMsg += ' (including deleted records)';\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', tmpMsg, 'ok');\n\t\t\t\t\ttmpSelf.startPolling();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync start failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t});\n\t}\n\n\tstopSync()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/sync/stop')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync stop requested.', 'warn');\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n\n\tstartPolling()\n\t{\n\t\tif (this.pict.AppData.DataCloner.SyncPollTimer) clearInterval(this.pict.AppData.DataCloner.SyncPollTimer);\n\t\tlet tmpSelf = this;\n\t\tthis.pict.AppData.DataCloner.SyncPollTimer = setInterval(function() { tmpSelf.pollSyncStatus(); }, 2000);\n\t\tthis.pollSyncStatus();\n\t}\n\n\tstopPolling()\n\t{\n\t\tif (this.pict.AppData.DataCloner.SyncPollTimer)\n\t\t{\n\t\t\tclearInterval(this.pict.AppData.DataCloner.SyncPollTimer);\n\t\t\tthis.pict.AppData.DataCloner.SyncPollTimer = null;\n\t\t}\n\t}\n\n\tpollSyncStatus()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/sync/status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.renderSyncProgress(pData);\n\n\t\t\t\tif (!pData.Running && !pData.Stopping)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.stopPolling();\n\t\t\t\t\tif (Object.keys(pData.Tables || {}).length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if any tables had errors or partial sync\n\t\t\t\t\t\tlet tmpTables = pData.Tables || {};\n\t\t\t\t\t\tlet tmpHasErrors = false;\n\t\t\t\t\t\tlet tmpHasPartial = false;\n\t\t\t\t\t\tlet tmpNames = Object.keys(tmpTables);\n\t\t\t\t\t\tfor (let i = 0; i < tmpNames.length; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpTables[tmpNames[i]].Status === 'Error') tmpHasErrors = true;\n\t\t\t\t\t\t\tif (tmpTables[tmpNames[i]].Status === 'Partial') tmpHasPartial = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (tmpHasErrors)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync finished with errors. Check the table below for details.', 'error');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (tmpHasPartial)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync finished. Some records were skipped (GUID conflicts or permission issues).', 'warn');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'ok');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync complete.', 'ok');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'ok');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Fetch the structured report\n\t\t\t\t\t\ttmpSelf.fetchSyncReport();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\t// Silently ignore poll errors\n\t\t\t});\n\t}\n\n\tfetchSyncReport()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/sync/report')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData && pData.ReportVersion)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.LastReport = pData;\n\t\t\t\t\ttmpSelf.renderSyncReport(pData);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\t// Ignore report fetch errors\n\t\t\t});\n\t}\n\n\trenderSyncReport(pReport)\n\t{\n\t\tlet tmpSection = document.getElementById('syncReportSection');\n\t\ttmpSection.style.display = '';\n\n\t\t// --- Summary Cards ---\n\t\tlet tmpCardsContainer = document.getElementById('reportSummaryCards');\n\t\tlet tmpOutcomeClass = 'outcome-' + pReport.Outcome.toLowerCase();\n\t\tlet tmpOutcomeColor = { Success: '#28a745', Partial: '#ffc107', Error: '#dc3545', Stopped: '#6c757d' }[pReport.Outcome] || '#666';\n\n\t\tlet tmpDurationSec = pReport.RunTimestamps.DurationSeconds || 0;\n\t\tlet tmpDurationStr = tmpDurationSec < 60 ? tmpDurationSec + 's' : Math.floor(tmpDurationSec / 60) + 'm ' + (tmpDurationSec % 60) + 's';\n\n\t\tlet tmpTotalSynced = pReport.Summary.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\tlet tmpTotalRecords = pReport.Summary.TotalRecords.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\n\t\ttmpCardsContainer.innerHTML = ''\n\t\t\t+ '<div class=\"report-card ' + tmpOutcomeClass + '\">'\n\t\t\t+ ' <div class=\"card-label\">Outcome</div>'\n\t\t\t+ ' <div class=\"card-value\" style=\"color:' + tmpOutcomeColor + '\">' + pReport.Outcome + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Mode</div>'\n\t\t\t+ ' <div class=\"card-value\">' + pReport.Config.SyncMode + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Duration</div>'\n\t\t\t+ ' <div class=\"card-value\">' + tmpDurationStr + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Tables</div>'\n\t\t\t+ ' <div class=\"card-value\">' + pReport.Summary.Complete + ' / ' + pReport.Summary.TotalTables + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Records</div>'\n\t\t\t+ ' <div class=\"card-value\">' + tmpTotalSynced + '</div>'\n\t\t\t+ ' <div style=\"font-size:0.75em; color:#888\">of ' + tmpTotalRecords + '</div>'\n\t\t\t+ '</div>';\n\n\t\t// --- Anomalies ---\n\t\tlet tmpAnomalyContainer = document.getElementById('reportAnomalies');\n\t\tif (pReport.Anomalies.length === 0)\n\t\t{\n\t\t\ttmpAnomalyContainer.innerHTML = '<div style=\"color:#28a745; font-weight:600; font-size:0.9em\">No anomalies detected.</div>';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpHtml = '<h4 style=\"margin:0 0 8px; color:#dc3545; font-size:0.95em\">Anomalies (' + pReport.Anomalies.length + ')</h4>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Type</th><th>Message</th></tr>';\n\t\t\tfor (let i = 0; i < pReport.Anomalies.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpAnomaly = pReport.Anomalies[i];\n\t\t\t\tlet tmpTypeColor = tmpAnomaly.Type === 'Error' ? '#dc3545' : (tmpAnomaly.Type === 'Partial' ? '#ffc107' : '#6c757d');\n\t\t\t\ttmpHtml += '<tr>';\n\t\t\t\ttmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Table) + '</strong></td>';\n\t\t\t\ttmpHtml += '<td style=\"color:' + tmpTypeColor + '\">' + tmpAnomaly.Type + '</td>';\n\t\t\t\ttmpHtml += '<td>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Message) + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\ttmpAnomalyContainer.innerHTML = tmpHtml;\n\t\t}\n\n\t\t// --- Top Tables by Duration ---\n\t\tlet tmpTopContainer = document.getElementById('reportTopTables');\n\t\tlet tmpTopCount = Math.min(10, pReport.Tables.length);\n\t\tif (tmpTopCount > 0)\n\t\t{\n\t\t\tlet tmpHtml = '<h4 style=\"margin:0 0 8px; font-size:0.95em; color:#444\">Top Tables by Duration</h4>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Duration</th><th>Records</th><th>Status</th></tr>';\n\t\t\tfor (let i = 0; i < tmpTopCount; i++)\n\t\t\t{\n\t\t\t\tlet tmpTable = pReport.Tables[i];\n\t\t\t\tlet tmpDur = tmpTable.DurationSeconds < 60 ? tmpTable.DurationSeconds + 's' : Math.floor(tmpTable.DurationSeconds / 60) + 'm ' + (tmpTable.DurationSeconds % 60) + 's';\n\t\t\t\tlet tmpRecs = tmpTable.Total.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\tlet tmpStatusColor = { Complete: '#28a745', Error: '#dc3545', Partial: '#ffc107' }[tmpTable.Status] || '#666';\n\t\t\t\ttmpHtml += '<tr>';\n\t\t\t\ttmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpTable.Name) + '</strong></td>';\n\t\t\t\ttmpHtml += '<td>' + tmpDur + '</td>';\n\t\t\t\ttmpHtml += '<td>' + tmpRecs + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"color:' + tmpStatusColor + '\">' + tmpTable.Status + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\ttmpTopContainer.innerHTML = tmpHtml;\n\t\t}\n\t}\n\n\tdownloadReport()\n\t{\n\t\tif (!this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'No report available.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpJson = JSON.stringify(this.pict.AppData.DataCloner.LastReport, null, '\\t');\n\t\tlet tmpBlob = new Blob([tmpJson], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\tlet tmpTimestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n\t\ttmpAnchor.download = 'DataCloner-Report-' + tmpTimestamp + '.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'Report downloaded.', 'ok');\n\t}\n\n\tcopyReport()\n\t{\n\t\tif (!this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'No report available.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpJson = JSON.stringify(this.pict.AppData.DataCloner.LastReport, null, '\\t');\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpJson).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('reportStatus', 'Report copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\trenderSyncProgress(pData)\n\t{\n\t\tlet tmpContainer = document.getElementById('syncProgress');\n\t\tlet tmpTables = pData.Tables || {};\n\t\tlet tmpTableNames = Object.keys(tmpTables);\n\n\t\tif (tmpTableNames.length === 0)\n\t\t{\n\t\t\ttmpContainer.innerHTML = '';\n\t\t\treturn;\n\t\t}\n\n\t\t// Categorize tables into sections, preserving original order for pending\n\t\tlet tmpSyncing = [];\n\t\tlet tmpPending = [];\n\t\tlet tmpCompleted = [];\n\t\tlet tmpErrors = [];\n\n\t\tfor (let i = 0; i < tmpTableNames.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpTableNames[i];\n\t\t\tlet tmpTable = tmpTables[tmpName];\n\n\t\t\tif (tmpTable.Status === 'Syncing')\n\t\t\t{\n\t\t\t\ttmpSyncing.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse if (tmpTable.Status === 'Pending')\n\t\t\t{\n\t\t\t\ttmpPending.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse if (tmpTable.Status === 'Complete')\n\t\t\t{\n\t\t\t\ttmpCompleted.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Error, Partial, or anything else\n\t\t\t\ttmpErrors.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t}\n\n\t\tlet tmpHtml = '';\n\t\tlet tmpSelf = this;\n\t\tlet fRenderRow = (pName, pTable) =>\n\t\t{\n\t\t\t// Calculate percentage\n\t\t\tlet tmpPct = 0;\n\t\t\tif (pTable.Total === 0 && (pTable.Status === 'Complete' || pTable.Status === 'Error'))\n\t\t\t{\n\t\t\t\ttmpPct = 100;\n\t\t\t}\n\t\t\telse if (pTable.Total > 0)\n\t\t\t{\n\t\t\t\ttmpPct = Math.round((pTable.Synced / pTable.Total) * 100);\n\t\t\t}\n\n\t\t\t// Color the progress bar based on status\n\t\t\tlet tmpBarColor = '#28a745'; // green\n\t\t\tif (pTable.Status === 'Error') tmpBarColor = '#dc3545';\n\t\t\telse if (pTable.Status === 'Partial') tmpBarColor = '#ffc107';\n\t\t\telse if (pTable.Status === 'Syncing') tmpBarColor = '#4a90d9';\n\t\t\telse if (pTable.Status === 'Pending') tmpBarColor = '#adb5bd';\n\n\t\t\t// Status badge\n\t\t\tlet tmpStatusBadge = pTable.Status;\n\t\t\tif (pTable.Status === 'Complete' && pTable.Total === 0) tmpStatusBadge = 'Complete (empty)';\n\t\t\tif (pTable.Status === 'Partial') tmpStatusBadge = 'Partial \\u26A0';\n\t\t\tif (pTable.Status === 'Error') tmpStatusBadge = 'Error \\u2716';\n\n\t\t\t// Details column\n\t\t\tlet tmpDetails = '';\n\t\t\tif (pTable.ErrorMessage) tmpDetails = pTable.ErrorMessage;\n\t\t\telse if (pTable.Skipped > 0) tmpDetails = pTable.Skipped + ' record(s) skipped';\n\t\t\telse if ((pTable.Errors || 0) > 0) tmpDetails = pTable.Errors + ' error(s)';\n\t\t\telse if (pTable.Status === 'Complete' && pTable.Total === 0) tmpDetails = 'No records on server';\n\t\t\telse if (pTable.Status === 'Complete') tmpDetails = '\\u2714 OK';\n\n\t\t\tlet tmpRow = '<tr>';\n\t\t\ttmpRow += '<td><strong>' + pName + '</strong></td>';\n\t\t\ttmpRow += '<td>' + tmpStatusBadge + '</td>';\n\t\t\ttmpRow += '<td>';\n\t\t\ttmpRow += '<div class=\"progress-bar-container\"><div class=\"progress-bar-fill\" style=\"width:' + tmpPct + '%; background:' + tmpBarColor + '\"></div></div>';\n\t\t\ttmpRow += ' ' + tmpPct + '%';\n\t\t\ttmpRow += '</td>';\n\t\t\ttmpRow += '<td>' + pTable.Synced + ' / ' + pTable.Total + '</td>';\n\t\t\ttmpRow += '<td>' + tmpDetails + '</td>';\n\t\t\ttmpRow += '</tr>';\n\t\t\treturn tmpRow;\n\t\t};\n\n\t\t// === SYNCING — currently active ===\n\t\tif (tmpSyncing.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header\">Syncing</div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpSyncing.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpSyncing[i].Name, tmpSyncing[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// === NEXT UP — pending tables in queue order ===\n\t\tif (tmpPending.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header\">Next Up <span class=\"sync-section-count\">' + tmpPending.length + '</span></div>';\n\t\t\t// Show at most 8 upcoming; collapse the rest\n\t\t\tlet tmpShowCount = Math.min(8, tmpPending.length);\n\t\t\ttmpHtml += '<table class=\"progress-table progress-table-muted\">';\n\t\t\tfor (let i = 0; i < tmpShowCount; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += '<tr><td>' + tmpPending[i].Name + '</td>';\n\t\t\t\tif (tmpPending[i].Data.Total > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpHtml += '<td class=\"sync-pending-count\">' + tmpPending[i].Data.Total.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + ' records</td>';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpHtml += '<td class=\"sync-pending-count\">—</td>';\n\t\t\t\t}\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\tif (tmpPending.length > tmpShowCount)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"sync-section-overflow\">+ ' + (tmpPending.length - tmpShowCount) + ' more table' + (tmpPending.length - tmpShowCount === 1 ? '' : 's') + '</div>';\n\t\t\t}\n\t\t}\n\n\t\t// === ERRORS — failed or partial ===\n\t\tif (tmpErrors.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header sync-section-header-error\">Errors <span class=\"sync-section-count\">' + tmpErrors.length + '</span></div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpErrors.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpErrors[i].Name, tmpErrors[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// === COMPLETED — successful tables ===\n\t\tif (tmpCompleted.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header sync-section-header-ok\">Completed <span class=\"sync-section-count\">' + tmpCompleted.length + '</span></div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpCompleted.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpCompleted[i].Name, tmpCompleted[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\t}\n}\n\nmodule.exports = DataClonerSyncView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Sync',\n\tDefaultRenderable: 'DataCloner-Sync',\n\tDefaultDestinationAddress: '#DataCloner-Section-Sync',\n\tCSS: /*css*/`\n.progress-table { width: 100%; border-collapse: collapse; margin-top: 4px; margin-bottom: 4px; }\n.progress-table th, .progress-table td { text-align: left; padding: 6px 12px; border-bottom: 1px solid #eee; font-size: 0.9em; }\n.progress-table th { background: #f8f9fa; font-weight: 600; }\n.progress-table-muted td { color: #888; padding: 3px 12px; font-size: 0.85em; border-bottom: 1px solid #f4f5f6; }\n.progress-bar-container { width: 120px; height: 16px; background: #e9ecef; border-radius: 8px; overflow: hidden; display: inline-block; vertical-align: middle; }\n.progress-bar-fill { height: 100%; background: #28a745; transition: width 0.3s; }\n.sync-section-header { font-size: 0.8em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: #4a90d9; padding: 10px 0 2px 0; margin-top: 6px; border-top: 1px solid #e0e0e0; }\n.sync-section-header:first-child { border-top: none; margin-top: 10px; }\n.sync-section-header-error { color: #dc3545; }\n.sync-section-header-ok { color: #28a745; }\n.sync-section-count { font-weight: 400; color: #999; font-size: 0.95em; }\n.sync-section-overflow { font-size: 0.8em; color: #aaa; padding: 2px 12px 6px; }\n.sync-pending-count { text-align: right; color: #aaa; font-size: 0.85em; }\n.report-card { background: #f8f9fa; border-radius: 8px; padding: 12px 16px; min-width: 140px; text-align: center; border: 1px solid #e9ecef; }\n.report-card .card-label { font-size: 0.8em; color: #666; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }\n.report-card .card-value { font-size: 1.4em; font-weight: 700; }\n.report-card.outcome-success { border-left: 4px solid #28a745; }\n.report-card.outcome-partial { border-left: 4px solid #ffc107; }\n.report-card.outcome-error { border-left: 4px solid #dc3545; }\n.report-card.outcome-stopped { border-left: 4px solid #6c757d; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Sync',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">5</div>\n\t<div class=\"accordion-card\" id=\"section5\" data-section=\"5\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section5')\">\n\t\t\t<div class=\"accordion-title\">Synchronize Data</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase5\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview5\">Initial sync, page size 100</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Sync'].startSync()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto5\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div style=\"display:flex; gap:8px; align-items:flex-end; margin-bottom:4px\">\n\t\t\t\t<div style=\"flex:0 0 150px\">\n\t\t\t\t\t<label for=\"pageSize\">Page Size</label>\n\t\t\t\t\t<input type=\"number\" id=\"pageSize\" value=\"100\" min=\"1\" max=\"10000\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 220px\">\n\t\t\t\t\t<label for=\"dateTimePrecisionMS\">Timestamp Precision (ms)</label>\n\t\t\t\t\t<input type=\"number\" id=\"dateTimePrecisionMS\" value=\"1000\" min=\"0\" max=\"60000\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; gap:8px\">\n\t\t\t\t\t<button class=\"success\" style=\"margin:0\" onclick=\"pict.views['DataCloner-Sync'].startSync()\">Start Sync</button>\n\t\t\t\t\t<button class=\"danger\" style=\"margin:0\" onclick=\"pict.views['DataCloner-Sync'].stopSync()\">Stop Sync</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div style=\"font-size:0.8em; color:#888; margin-bottom:10px; padding-left:158px\">Cross-DB tolerance for date comparison (default: 1000ms)</div>\n\n\t\t\t<div style=\"margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:6px\">Sync Mode</label>\n\t\t\t\t<div style=\"display:flex; gap:16px; align-items:center\">\n\t\t\t\t\t<label style=\"font-weight:normal; margin:0; cursor:pointer\">\n\t\t\t\t\t\t<input type=\"radio\" name=\"syncMode\" id=\"syncModeInitial\" value=\"Initial\" checked> Initial\n\t\t\t\t\t\t<span style=\"color:#888; font-size:0.85em\">(full clone — download all records)</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t<label style=\"font-weight:normal; margin:0; cursor:pointer\">\n\t\t\t\t\t\t<input type=\"radio\" name=\"syncMode\" id=\"syncModeOngoing\" value=\"Ongoing\"> Ongoing\n\t\t\t\t\t\t<span style=\"color:#888; font-size:0.85em\">(delta — only new/updated records since last sync)</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t<input type=\"checkbox\" id=\"syncDeletedRecords\">\n\t\t\t\t<label for=\"syncDeletedRecords\">Sync deleted records (fetch records marked Deleted=1 on source and mirror locally)</label>\n\t\t\t</div>\n\n\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t<input type=\"checkbox\" id=\"syncAdvancedIDPagination\">\n\t\t\t\t<label for=\"syncAdvancedIDPagination\">Use advanced ID pagination (faster for large tables; uses keyset pagination instead of OFFSET)</label>\n\t\t\t</div>\n\n\t\t\t<div class=\"inline-group\" style=\"margin-top:8px; margin-bottom:4px\">\n\t\t\t\t<div style=\"flex:0 0 200px\">\n\t\t\t\t\t<label for=\"syncMaxRecords\">Max Records per Entity</label>\n\t\t\t\t\t<input type=\"number\" id=\"syncMaxRecords\" value=\"\" min=\"0\" placeholder=\"0 = unlimited\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; align-items:flex-end; padding-bottom:2px\">\n\t\t\t\t\t<div class=\"checkbox-row\" style=\"margin-bottom:0\">\n\t\t\t\t\t\t<input type=\"checkbox\" id=\"syncLogFile\" checked>\n\t\t\t\t\t\t<label for=\"syncLogFile\">Write log file</label>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div id=\"syncStatus\"></div>\n\t\t\t<div id=\"syncProgress\"></div>\n\n\t\t\t<!-- Sync Report (appears after sync completes) -->\n\t\t\t<div id=\"syncReportSection\" style=\"display:none; margin-top:16px; padding-top:16px; border-top:2px solid #ddd\">\n\t\t\t\t<h3 style=\"margin:0 0 12px; font-size:1.1em\">Sync Report</h3>\n\n\t\t\t\t<!-- Summary cards -->\n\t\t\t\t<div id=\"reportSummaryCards\" style=\"display:flex; gap:12px; flex-wrap:wrap; margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Anomalies -->\n\t\t\t\t<div id=\"reportAnomalies\" style=\"margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Top tables by duration -->\n\t\t\t\t<div id=\"reportTopTables\" style=\"margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Buttons -->\n\t\t\t\t<div style=\"display:flex; gap:8px\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Sync'].downloadReport()\">Download Report JSON</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Sync'].copyReport()\">Copy Report</button>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"reportStatus\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Sync',\n\t\t\tTemplateHash: 'DataCloner-Sync',\n\t\t\tDestinationAddress: '#DataCloner-Section-Sync'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}],26:[function(require,module,exports){\nconst libPictView = require('pict-view');\n\nclass DataClonerViewDataView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tpopulateViewTableDropdown()\n\t{\n\t\tlet tmpSelect = document.getElementById('viewTable');\n\t\tif (!tmpSelect) return;\n\t\tlet tmpCurrentValue = tmpSelect.value;\n\n\t\ttmpSelect.innerHTML = '';\n\n\t\tlet tmpDeployedTables = this.pict.AppData.DataCloner.DeployedTables;\n\n\t\tif (!tmpDeployedTables || tmpDeployedTables.length === 0)\n\t\t{\n\t\t\tlet tmpOpt = document.createElement('option');\n\t\t\ttmpOpt.value = '';\n\t\t\ttmpOpt.textContent = '\\u2014 deploy tables first \\u2014';\n\t\t\ttmpSelect.appendChild(tmpOpt);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = 0; i < tmpDeployedTables.length; i++)\n\t\t{\n\t\t\tlet tmpOpt = document.createElement('option');\n\t\t\ttmpOpt.value = tmpDeployedTables[i];\n\t\t\ttmpOpt.textContent = tmpDeployedTables[i];\n\t\t\ttmpSelect.appendChild(tmpOpt);\n\t\t}\n\n\t\t// Restore previous selection if it exists\n\t\tif (tmpCurrentValue)\n\t\t{\n\t\t\ttmpSelect.value = tmpCurrentValue;\n\t\t}\n\t}\n\n\tloadTableData()\n\t{\n\t\tlet tmpTable = document.getElementById('viewTable').value;\n\t\tlet tmpLimit = parseInt(document.getElementById('viewLimit').value, 10) || 100;\n\n\t\tif (!tmpTable)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('viewStatus', 'Select a table first.', 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('viewStatus', 'Loading ' + tmpTable + '...', 'info');\n\t\tdocument.getElementById('viewDataContainer').innerHTML = '';\n\n\t\tlet tmpSelf = this;\n\t\t// Use the standard Meadow CRUD list endpoint: /1.0/{Entity}s/0/{Cap}\n\t\tthis.pict.providers.DataCloner.api('GET', '/1.0/' + tmpTable + 's/0/' + tmpLimit)\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (!Array.isArray(pData))\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', 'Unexpected response (not an array). The table may not be deployed yet.', 'error');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', pData.length + ' row(s) returned' + (pData.length >= tmpLimit ? ' (limit reached \\u2014 increase Max Rows to see more)' : '') + '.', 'ok');\n\t\t\t\ttmpSelf.renderDataTable(pData);\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n\n\trenderDataTable(pRows)\n\t{\n\t\tlet tmpContainer = document.getElementById('viewDataContainer');\n\n\t\tif (!pRows || pRows.length === 0)\n\t\t{\n\t\t\ttmpContainer.innerHTML = '<p style=\"color:#666; font-size:0.9em; padding:8px\">No rows.</p>';\n\t\t\treturn;\n\t\t}\n\n\t\t// Collect all column names from the first row\n\t\tlet tmpColumns = Object.keys(pRows[0]);\n\n\t\tlet tmpHtml = '<table class=\"data-table\">';\n\t\ttmpHtml += '<thead><tr>';\n\t\tfor (let c = 0; c < tmpColumns.length; c++)\n\t\t{\n\t\t\ttmpHtml += '<th>' + this.pict.providers.DataCloner.escapeHtml(tmpColumns[c]) + '</th>';\n\t\t}\n\t\ttmpHtml += '</tr></thead>';\n\n\t\ttmpHtml += '<tbody>';\n\t\tfor (let r = 0; r < pRows.length; r++)\n\t\t{\n\t\t\ttmpHtml += '<tr>';\n\t\t\tfor (let c = 0; c < tmpColumns.length; c++)\n\t\t\t{\n\t\t\t\tlet tmpVal = pRows[r][tmpColumns[c]];\n\t\t\t\tlet tmpDisplay = (tmpVal === null || tmpVal === undefined) ? '' : String(tmpVal);\n\t\t\t\ttmpHtml += '<td title=\"' + this.pict.providers.DataCloner.escapeHtml(tmpDisplay) + '\">' + this.pict.providers.DataCloner.escapeHtml(tmpDisplay) + '</td>';\n\t\t\t}\n\t\t\ttmpHtml += '</tr>';\n\t\t}\n\t\ttmpHtml += '</tbody></table>';\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\t}\n}\n\nmodule.exports = DataClonerViewDataView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-ViewData',\n\tDefaultRenderable: 'DataCloner-ViewData',\n\tDefaultDestinationAddress: '#DataCloner-Section-ViewData',\n\tCSS: /*css*/`\n.data-table { width: 100%; border-collapse: collapse; font-size: 0.8em; font-family: monospace; }\n.data-table th { background: #f8f9fa; font-weight: 600; text-align: left; padding: 4px 8px; border: 1px solid #ddd; white-space: nowrap; position: sticky; top: 0; }\n.data-table td { padding: 4px 8px; border: 1px solid #eee; white-space: nowrap; max-width: 300px; overflow: hidden; text-overflow: ellipsis; }\n.data-table tr:nth-child(even) { background: #fafafa; }\n.data-table tr:hover { background: #f0f7ff; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-ViewData',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">7</div>\n\t<div class=\"accordion-card\" id=\"section7\" data-section=\"7\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section7')\">\n\t\t\t<div class=\"accordion-title\">View Data</div>\n\t\t\t<div class=\"accordion-preview\" id=\"preview7\">Browse synced table data</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t<label for=\"viewTable\">Table</label>\n\t\t\t\t\t<select id=\"viewTable\">\n\t\t\t\t\t\t<option value=\"\">\\u2014 deploy tables first \\u2014</option>\n\t\t\t\t\t</select>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 120px\">\n\t\t\t\t\t<label for=\"viewLimit\">Max Rows</label>\n\t\t\t\t\t<input type=\"number\" id=\"viewLimit\" value=\"100\" min=\"1\" max=\"10000\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; align-items:flex-end\">\n\t\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-ViewData'].loadTableData()\">Load</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div id=\"viewStatus\"></div>\n\t\t\t<div id=\"viewDataContainer\" style=\"overflow-x:auto; margin-top:10px\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-ViewData',\n\t\t\tTemplateHash: 'DataCloner-ViewData',\n\t\t\tDestinationAddress: '#DataCloner-Section-ViewData'\n\t\t}\n\t]\n};\n\n},{\"pict-view\":13}]},{},[17])(17)\n});\n\n","(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()","module.exports={\n \"name\": \"fable-serviceproviderbase\",\n \"version\": \"3.0.19\",\n \"description\": \"Simple base classes for fable services.\",\n \"main\": \"source/Fable-ServiceProviderBase.js\",\n \"scripts\": {\n \"start\": \"node source/Fable-ServiceProviderBase.js\",\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"types\": \"tsc -p ./tsconfig.build.json\",\n \"check\": \"tsc -p . --noEmit\"\n },\n \"types\": \"types/source/Fable-ServiceProviderBase.d.ts\",\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/stevenvelozo/fable-serviceproviderbase.git\"\n },\n \"keywords\": [\n \"entity\",\n \"behavior\"\n ],\n \"author\": \"Steven Velozo <steven@velozo.com> (http://velozo.com/)\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/fable-serviceproviderbase/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/fable-serviceproviderbase\",\n \"devDependencies\": {\n \"@types/mocha\": \"^10.0.10\",\n \"fable\": \"^3.1.62\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n }\n}\n","/**\n* Fable Service Base\n* @author <steven@velozo.com>\n*/\n\nconst libPackage = require('../package.json');\n\nclass FableServiceProviderBase\n{\n\t/**\n\t * The constructor can be used in two ways:\n\t * 1) With a fable, options object and service hash (the options object and service hash are optional)a\n\t * 2) With an object or nothing as the first parameter, where it will be treated as the options object\n\t *\n\t * @param {import('fable')|Record<string, any>} [pFable] - (optional) The fable instance, or the options object if there is no fable\n\t * @param {Record<string, any>|string} [pOptions] - (optional) The options object, or the service hash if there is no fable\n\t * @param {string} [pServiceHash] - (optional) The service hash to identify this service instance\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t/** @type {import('fable')} */\n\t\tthis.fable;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.options;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.services;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.servicesMap;\n\n\t\t// Check if a fable was passed in; connect it if so\n\t\tif ((typeof(pFable) === 'object') && pFable.isFable)\n\t\t{\n\t\t\tthis.connectFable(pFable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.fable = false;\n\t\t}\n\n\t\t// Initialize the services map if it wasn't passed in\n\t\t/** @type {Record<string, any>} */\n\t\tthis._PackageFableServiceProvider = libPackage;\n\n\t\t// initialize options and UUID based on whether the fable was passed in or not.\n\t\tif (this.fable)\n\t\t{\n\t\t\tthis.UUID = pFable.getUUID();\n\t\t\tthis.options = (typeof(pOptions) === 'object') ? pOptions\n\t\t\t\t\t\t\t: {};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// With no fable, check to see if there was an object passed into either of the first two\n\t\t\t// Parameters, and if so, treat it as the options object\n\t\t\tthis.options = ((typeof(pFable) === 'object') && !pFable.isFable) ? pFable\n\t\t\t\t\t\t\t: (typeof(pOptions) === 'object') ? pOptions\n\t\t\t\t\t\t\t: {};\n\t\t\tthis.UUID = `CORE-SVC-${Math.floor((Math.random() * (99999 - 10000)) + 10000)}`\n\t\t}\n\n\t\t// It's expected that the deriving class will set this\n\t\tthis.serviceType = `Unknown-${this.UUID}`;\n\n\t\t// The service hash is used to identify the specific instantiation of the service in the services map\n\t\tthis.Hash = (typeof(pServiceHash) === 'string') ? pServiceHash \n\t\t\t\t\t: (!this.fable && (typeof(pOptions) === 'string')) ? pOptions\n\t\t\t\t\t: `${this.UUID}`;\n\t}\n\n\t/**\n\t * @param {import('fable')} pFable\n\t */\n\tconnectFable(pFable)\n\t{\n\t\tif ((typeof(pFable) !== 'object') || (!pFable.isFable))\n\t\t{\n\t\t\tlet tmpErrorMessage = `Fable Service Provider Base: Cannot connect to Fable, invalid Fable object passed in. The pFable parameter was a [${typeof(pFable)}].}`;\n\t\t\tconsole.log(tmpErrorMessage);\n\t\t\treturn new Error(tmpErrorMessage);\n\t\t}\n\n\t\tif (!this.fable)\n\t\t{\n\t\t\tthis.fable = pFable;\n\t\t}\n\n\t\tif (!this.log)\n\t\t{\n\t\t\tthis.log = this.fable.Logging;\n\t\t}\n\t\tif (!this.services)\n\t\t{\n\t\t\tthis.services = this.fable.services;\n\t\t}\n\n\t\tif (!this.servicesMap)\n\t\t{\n\t\t\tthis.servicesMap = this.fable.servicesMap;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tstatic isFableService = true;\n}\n\nmodule.exports = FableServiceProviderBase;\n\n// This is left here in case we want to go back to having different code/base class for \"core\" services\nmodule.exports.CoreServiceProviderBase = FableServiceProviderBase;\n","module.exports={\n \"name\": \"pict-application\",\n \"version\": \"1.0.33\",\n \"description\": \"Application base class for a pict view-based application\",\n \"main\": \"source/Pict-Application.js\",\n \"scripts\": {\n \"test\": \"npx quack test\",\n \"start\": \"node source/Pict-Application.js\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-application-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-application-dev -p 30001:8080 -p 38086:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-application\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-application-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-application-dev /bin/bash\",\n \"tests\": \"npx quack test -g\",\n \"lint\": \"eslint source/**\",\n \"types\": \"tsc -p .\"\n },\n \"types\": \"types/source/Pict-Application.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-application.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-application/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-application#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.28.0\",\n \"browser-env\": \"^3.3.0\",\n \"eslint\": \"^9.28.0\",\n \"pict\": \"^1.0.348\",\n \"pict-provider\": \"^1.0.10\",\n \"pict-view\": \"^1.0.66\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"dependencies\": {\n \"fable-serviceproviderbase\": \"^3.0.19\"\n }\n}\n","const libFableServiceBase = require('fable-serviceproviderbase')\n\nconst libPackage = require('../package.json');\n\nconst defaultPictSettings = (\n\t{\n\t\tName: 'DefaultPictApplication',\n\n\t\t// The main \"viewport\" is the view that is used to host our application\n\t\tMainViewportViewIdentifier: 'Default-View',\n\t\tMainViewportRenderableHash: false,\n\t\tMainViewportDestinationAddress: false,\n\t\tMainViewportDefaultDataAddress: false,\n\n\t\t// Whether or not we should automatically render the main viewport and other autorender views after we initialize the pict application\n\t\tAutoSolveAfterInitialize: true,\n\t\tAutoRenderMainViewportViewAfterInitialize: true,\n\t\tAutoRenderViewsAfterInitialize: false,\n\t\tAutoLoginAfterInitialize: false,\n\t\tAutoLoadDataAfterLogin: false,\n\n\t\tConfigurationOnlyViews: [],\n\n\t\tManifests: {},\n\t\t// The prefix to prepend on all template destination hashes\n\t\tIdentifierAddressPrefix: 'PICT-'\n\t});\n\n/**\n * Base class for pict applications.\n */\nclass PictApplication extends libFableServiceBase\n{\n\t/**\n\t * @param {import('fable')} pFable\n\t * @param {Record<string, any>} [pOptions]\n\t * @param {string} [pServiceHash]\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tlet tmpCarryOverConfiguration = (typeof(pFable.settings.PictApplicationConfiguration) === 'object') ? pFable.settings.PictApplicationConfiguration : {};\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictSettings)), tmpCarryOverConfiguration, pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\t/** @type {any} */\n\t\tthis.options;\n\t\t/** @type {any} */\n\t\tthis.log;\n\t\t/** @type {import('pict') & import('fable')} */\n\t\tthis.fable;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {string} */\n\t\tthis.Hash;\n\t\t/**\n\t\t * @type {{ [key: string]: any }}\n\t\t */\n\t\tthis.servicesMap;\n\n\t\tthis.serviceType = 'PictApplication';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\n\t\t// Convenience and consistency naming\n\t\tthis.pict = this.fable;\n\t\t// Wire in the essential Pict state\n\t\t/** @type {Record<string, any>} */\n\t\tthis.AppData = this.fable.AppData;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.Bundle = this.fable.Bundle;\n\n\t\t/** @type {number} */\n\t\tthis.initializeTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastSolvedTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastLoginTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastMarshalFromViewsTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastMarshalToViewsTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastAutoRenderTimestamp;\n\t\t/** @type {number} */\n\t\tthis.lastLoadDataTimestamp;\n\n\t\t// Load all the manifests for the application\n\t\tlet tmpManifestKeys = Object.keys(this.options.Manifests);\n\t\tif (tmpManifestKeys.length > 0)\n\t\t{\n\t\t\tfor (let i = 0; i < tmpManifestKeys.length; i++)\n\t\t\t{\n\t\t\t\t// Load each manifest\n\t\t\t\tlet tmpManifestKey = tmpManifestKeys[i];\n\t\t\t\tthis.fable.instantiateServiceProvider('Manifest', this.options.Manifests[tmpManifestKey], tmpManifestKey);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Solve All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonPreSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onPreSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonPreSolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeSolveAsync(fCallback)\n\t{\n\t\tthis.onBeforeSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonSolveAsync(fCallback)\n\t{\n\t\tthis.onSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tsolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing solve() function...`)\n\t\t}\n\n\t\t// Walk through any loaded providers and solve them as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSolve.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpProvidersToSolve.length; i++)\n\t\t{\n\t\t\ttmpProvidersToSolve[i].solve(tmpProvidersToSolve[i]);\n\t\t}\n\n\t\tthis.onBeforeSolve();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t{\n\t\t\t\ttmpViewsToSolve.push(tmpView);\n\t\t\t}\n\t\t}\n\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpViewsToSolve.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\tfor (let i = 0; i < tmpViewsToSolve.length; i++)\n\t\t{\n\t\t\ttmpViewsToSolve[i].solve();\n\t\t}\n\t\tthis.onSolve();\n\t\tthis.onAfterSolve();\n\t\tthis.lastSolvedTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));\n\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\t\t// Walk through any loaded providers and solve them as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSolve.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpProvidersToSolve.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvidersToSolve[i].solveAsync.bind(tmpProvidersToSolve[i]));\n\t\t}\n\n\t\t// Walk through any loaded views and solve them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToSolve = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoSolveWithApp)\n\t\t\t{\n\t\t\t\ttmpViewsToSolve.push(tmpView);\n\t\t\t}\n\t\t}\n\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpViewsToSolve.sort((a, b) => { return a.options.AutoSolveOrdinal - b.options.AutoSolveOrdinal; });\n\t\tfor (let i = 0; i < tmpViewsToSolve.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToSolve[i].solveAsync.bind(tmpViewsToSolve[i]));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSolvedTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterSolveAsync(fCallback)\n\t{\n\t\tthis.onAfterSolve();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application Login */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tloginAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeLoginAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onLoginAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterLoginAsync.bind(this));\n\n\t\t// check and see if we should automatically trigger a data load\n\t\tif (this.options.AutoLoadDataAfterLogin)\n\t\t{\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tif (!this.isLoggedIn())\n\t\t\t\t{\n\t\t\t\t\treturn fNext();\n\t\t\t\t}\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto loading data after login...`);\n\t\t\t\t}\n\t\t\t\t//TODO: should data load errors funnel here? this creates a weird coupling between login and data load callbacks\n\t\t\t\tthis.loadDataAsync((pError) =>\n\t\t\t\t{\n\t\t\t\t\tfNext(pError);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loginAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastLoginTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Check if the application state is logged in. Defaults to true. Override this method in your application based on login requirements.\n\t *\n\t * @return {boolean}\n\t */\n\tisLoggedIn()\n\t{\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterLoginAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterLoginAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application LoadData */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tloadDataAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeLoadDataAsync.bind(this));\n\n\t\t// Walk through any loaded providers and load their data as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToLoadData = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoLoadDataWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToLoadData.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToLoadData.sort((a, b) => { return a.options.AutoLoadDataOrdinal - b.options.AutoLoadDataOrdinal; });\n\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onBeforeLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onLoadDataAsync.bind(this));\n\n\t\t//TODO: think about ways to parallelize these\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onAfterLoadDataAsync.bind(this));\n\n\t\tfor (const tmpProvider of tmpProvidersToLoadData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onAfterLoadDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t/** @param {Error} [pError] */\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} loadDataAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastLoadDataTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Application SaveData */\n\t/* -------------------------------------------------------------------------- */\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tsaveDataAsync(fCallback)\n\t{\n\t\tconst tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\tlet tmpCallback = fCallback;\n\n\t\tif (typeof(tmpCallback) !== 'function')\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSaveDataAsync.bind(this));\n\n\t\t// Walk through any loaded providers and load their data as well.\n\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\tlet tmpProvidersToSaveData = [];\n\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t{\n\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\tif (tmpProvider.options.AutoSaveDataWithApp)\n\t\t\t{\n\t\t\t\ttmpProvidersToSaveData.push(tmpProvider);\n\t\t\t}\n\t\t}\n\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\ttmpProvidersToSaveData.sort((a, b) => { return a.options.AutoSaveDataOrdinal - b.options.AutoSaveDataOrdinal; });\n\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onBeforeSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onSaveDataAsync.bind(this));\n\n\t\t//TODO: think about ways to parallelize these\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onAfterSaveDataAsync.bind(this));\n\n\t\tfor (const tmpProvider of tmpProvidersToSaveData)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpProvider.onAfterSaveDataAsync.bind(tmpProvider));\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t/** @param {Error} [pError] */\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} saveDataAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSaveDataTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialize Application */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\n\t\t\tif ('ConfigurationOnlyViews' in this.options)\n\t\t\t{\n\t\t\t\t// Load all the configuration only views\n\t\t\t\tfor (let i = 0; i < this.options.ConfigurationOnlyViews.length; i++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpViewIdentifier = (typeof(this.options.ConfigurationOnlyViews[i].ViewIdentifier) === 'undefined') ? `AutoView-${this.fable.getUUID()}`\n\t\t\t\t\t\t\t\t\t\t\t: this.options.ConfigurationOnlyViews[i].ViewIdentifier;\n\t\t\t\t\tthis.log.info(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} adding configuration only view: ${tmpViewIdentifier}`);\n\t\t\t\t\tthis.pict.addView(tmpViewIdentifier, this.options.ConfigurationOnlyViews[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.onInitialize();\n\n\t\t\t// Walk through any loaded providers and initialize them as well.\n\t\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\t\tlet tmpProvidersToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\t\tif (tmpProvider.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpProvidersToInitialize.push(tmpProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpProvidersToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpProvidersToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpProvidersToInitialize[i].initialize();\n\t\t\t}\n\n\t\t\t// Now walk through any loaded views and initialize them as well.\n\t\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t\tlet tmpViewsToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpViewsToInitialize.push(tmpView);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpViewsToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpViewsToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpViewsToInitialize[i].initialize();\n\t\t\t}\n\n\t\t\tthis.onAfterInitialize();\n\t\t\tif (this.options.AutoSolveAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto solving after initialization...`);\n\t\t\t\t}\n\t\t\t\t// Solve the template synchronously\n\t\t\t\tthis.solve();\n\t\t\t}\n\t\t\t// Now check and see if we should automatically render as well\n\t\t\tif (this.options.AutoRenderMainViewportViewAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto rendering after initialization...`);\n\t\t\t\t}\n\t\t\t\t// Render the template synchronously\n\t\t\t\tthis.render();\n\t\t\t}\n\t\t\tthis.initializeTimestamp = this.fable.log.getTimeStamp();\n\t\t\tthis.onCompletionOfInitialize();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync:`);\n\t\t}\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 3)\n\t\t\t{\n\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning initialization...`);\n\t\t\t}\n\n\t\t\tif ('ConfigurationOnlyViews' in this.options)\n\t\t\t{\n\t\t\t\t// Load all the configuration only views\n\t\t\t\tfor (let i = 0; i < this.options.ConfigurationOnlyViews.length; i++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpViewIdentifier = (typeof(this.options.ConfigurationOnlyViews[i].ViewIdentifier) === 'undefined') ? `AutoView-${this.fable.getUUID()}`\n\t\t\t\t\t\t\t\t\t\t\t: this.options.ConfigurationOnlyViews[i].ViewIdentifier;\n\t\t\t\t\tthis.log.info(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} adding configuration only view: ${tmpViewIdentifier}`);\n\t\t\t\t\tthis.pict.addView(tmpViewIdentifier, this.options.ConfigurationOnlyViews[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\n\t\t\t// Walk through any loaded providers and solve them as well.\n\t\t\tlet tmpLoadedProviders = Object.keys(this.pict.providers);\n\t\t\tlet tmpProvidersToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedProviders.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpProvider = this.pict.providers[tmpLoadedProviders[i]];\n\t\t\t\tif (tmpProvider.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpProvidersToInitialize.push(tmpProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)\n\t\t\ttmpProvidersToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpProvidersToInitialize.length; i++)\n\t\t\t{\n\t\t\t\ttmpAnticipate.anticipate(tmpProvidersToInitialize[i].initializeAsync.bind(tmpProvidersToInitialize[i]));\n\t\t\t}\n\n\t\t\t// Now walk through any loaded views and initialize them as well.\n\t\t\t// TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.\n\t\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t\tlet tmpViewsToInitialize = [];\n\t\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\t\tif (tmpView.options.AutoInitialize)\n\t\t\t\t{\n\t\t\t\t\ttmpViewsToInitialize.push(tmpView);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort the views by their priority\n\t\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\t\ttmpViewsToInitialize.sort((a, b) => { return a.options.AutoInitializeOrdinal - b.options.AutoInitializeOrdinal; });\n\t\t\tfor (let i = 0; i < tmpViewsToInitialize.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpView = tmpViewsToInitialize[i];\n\t\t\t\ttmpAnticipate.anticipate(tmpView.initializeAsync.bind(tmpView));\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\tif (this.options.AutoLoginAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto login (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.loginAsync.bind(this));\n\t\t\t}\n\n\t\t\tif (this.options.AutoSolveAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto solving (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.solveAsync.bind(this));\n\t\t\t}\n\n\t\t\tif (this.options.AutoRenderMainViewportViewAfterInitialize)\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 1)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} auto rendering (asynchronously) after initialization...`);\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(this.renderMainViewportAsync.bind(this));\n\t\t\t}\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initializeAsync Error: ${pError.message || pError}`, { stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\tthis.initializeTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn tmpCallback();\n\t\t\t\t});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn this.onCompletionOfInitializeAsync(tmpCallback);\n\t\t}\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonCompletionOfInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onCompletionOfInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonCompletionOfInitializeAsync(fCallback)\n\t{\n\t\tthis.onCompletionOfInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal Data From All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tmarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing marshalFromViews() function...`)\n\t\t}\n\t\tthis.onBeforeMarshalFromViews();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalFromViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalFromViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalFromViews.length; i++)\n\t\t{\n\t\t\ttmpViewsToMarshalFromViews[i].marshalFromView();\n\t\t}\n\t\tthis.onMarshalFromViews();\n\t\tthis.onAfterMarshalFromViews();\n\t\tthis.lastMarshalFromViewsTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tmarshalFromViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalFromViewsAsync.bind(this));\n\t\t// Walk through any loaded views and marshalFromViews them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalFromViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalFromViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalFromViews.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToMarshalFromViews[i].marshalFromViewAsync.bind(tmpViewsToMarshalFromViews[i]));\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onMarshalFromViewsAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalFromViewsAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewsAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalFromViewsTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterMarshalFromViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterMarshalFromViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterMarshalFromViewsAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalFromViews();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal Data To All Views */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tmarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} executing marshalToViews() function...`)\n\t\t}\n\t\tthis.onBeforeMarshalToViews();\n\t\t// Now walk through any loaded views and initialize them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalToViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalToViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalToViews.length; i++)\n\t\t{\n\t\t\ttmpViewsToMarshalToViews[i].marshalToView();\n\t\t}\n\t\tthis.onMarshalToViews();\n\t\tthis.onAfterMarshalToViews();\n\t\tthis.lastMarshalToViewsTimestamp = this.fable.log.getTimeStamp();\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tmarshalToViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : false;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalToViewsAsync.bind(this));\n\t\t// Walk through any loaded views and marshalToViews them as well.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\tlet tmpViewsToMarshalToViews = [];\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\ttmpViewsToMarshalToViews.push(tmpView);\n\t\t}\n\t\tfor (let i = 0; i < tmpViewsToMarshalToViews.length; i++)\n\t\t{\n\t\t\ttmpAnticipate.anticipate(tmpViewsToMarshalToViews[i].marshalToViewAsync.bind(tmpViewsToMarshalToViews[i]));\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onMarshalToViewsAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalToViewsAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewsAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalToViewsTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterMarshalToViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterMarshalToViews:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterMarshalToViewsAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalToViews();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Render View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * @return {boolean}\n\t */\n\tonBeforeRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onBeforeRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonBeforeRenderAsync(fCallback)\n\t{\n\t\tthis.onBeforeRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {string} [pViewIdentifier] - The hash of the view to render. By default, the main viewport view is rendered.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string} [pTemplateDataAddress] - The address where the data for the template is stored.\n\t *\n\t * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?\n\t */\n\trender(pViewIdentifier, pRenderableHash, pRenderDestinationAddress, pTemplateDataAddress)\n\t{\n\t\tlet tmpViewIdentifier = (typeof(pViewIdentifier) !== 'string') ? this.options.MainViewportViewIdentifier : pViewIdentifier;\n\t\tlet tmpRenderableHash = (typeof(pRenderableHash) !== 'string') ? this.options.MainViewportRenderableHash : pRenderableHash;\n\t\tlet tmpRenderDestinationAddress = (typeof(pRenderDestinationAddress) !== 'string') ? this.options.MainViewportDestinationAddress : pRenderDestinationAddress;\n\t\tlet tmpTemplateDataAddress = (typeof(pTemplateDataAddress) !== 'string') ? this.options.MainViewportDefaultDataAddress : pTemplateDataAddress;\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} VIEW Renderable[${tmpRenderableHash}] Destination[${tmpRenderDestinationAddress}] TemplateDataAddress[${tmpTemplateDataAddress}] render:`);\n\t\t}\n\n\t\tthis.onBeforeRender();\n\n\t\t// Now get the view (by hash) from the loaded views\n\t\tlet tmpView = (typeof (tmpViewIdentifier) === 'string') ? this.servicesMap.PictView[tmpViewIdentifier] : false;\n\t\tif (!tmpView)\n\t\t{\n\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} could not render from View ${tmpViewIdentifier} because it is not a valid view.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.onRender();\n\n\t\ttmpView.render(tmpRenderableHash, tmpRenderDestinationAddress, tmpTemplateDataAddress);\n\n\t\tthis.onAfterRender();\n\n\t\treturn true;\n\t}\n\t/**\n\t * @return {boolean}\n\t */\n\tonRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonRenderAsync(fCallback)\n\t{\n\t\tthis.onRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {string|((error?: Error) => void)} pViewIdentifier - The hash of the view to render. By default, the main viewport view is rendered. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pRenderableHash] - The hash of the renderable to render. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pRenderDestinationAddress] - The address where the renderable will be rendered. (or the callback)\n\t * @param {string|((error?: Error) => void)} [pTemplateDataAddress] - The address where the data for the template is stored. (or the callback)\n\t * @param {(error?: Error) => void} [fCallback] - The callback, if all other parameters are provided.\n\t *\n\t * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?\n\t */\n\trenderAsync(pViewIdentifier, pRenderableHash, pRenderDestinationAddress, pTemplateDataAddress, fCallback)\n\t{\n\t\tlet tmpViewIdentifier = (typeof(pViewIdentifier) !== 'string') ? this.options.MainViewportViewIdentifier : pViewIdentifier;\n\t\tlet tmpRenderableHash = (typeof(pRenderableHash) !== 'string') ? this.options.MainViewportRenderableHash : pRenderableHash;\n\t\tlet tmpRenderDestinationAddress = (typeof(pRenderDestinationAddress) !== 'string') ? this.options.MainViewportDestinationAddress : pRenderDestinationAddress;\n\t\tlet tmpTemplateDataAddress = (typeof(pTemplateDataAddress) !== 'string') ? this.options.MainViewportDefaultDataAddress : pTemplateDataAddress;\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateDataAddress) === 'function') ? pTemplateDataAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\t(typeof(pViewIdentifier) === 'function') ? pViewIdentifier :\n\t\t\t\t\t\t\tfalse;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} VIEW Renderable[${tmpRenderableHash}] Destination[${tmpRenderDestinationAddress}] TemplateDataAddress[${tmpTemplateDataAddress}] renderAsync:`);\n\t\t}\n\n\t\tlet tmpRenderAnticipate = this.fable.newAnticipate();\n\n\t\ttmpRenderAnticipate.anticipate(this.onBeforeRenderAsync.bind(this));\n\n\t\tlet tmpView = (typeof (tmpViewIdentifier) === 'string') ? this.servicesMap.PictView[tmpViewIdentifier] : false;\n\t\tif (!tmpView)\n\t\t{\n\t\t\tlet tmpErrorMessage = `PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} could not asynchronously render from View ${tmpViewIdentifier} because it is not a valid view.`;\n\t\t\tif (this.pict.LogNoisiness > 3)\n\t\t\t{\n\t\t\t\tthis.log.error(tmpErrorMessage);\n\t\t\t}\n\t\t\treturn tmpCallback(new Error(tmpErrorMessage));\n\t\t}\n\n\t\ttmpRenderAnticipate.anticipate(this.onRenderAsync.bind(this));\n\n\t\ttmpRenderAnticipate.anticipate(\n\t\t\t(fNext) =>\n\t\t\t{\n\t\t\t\ttmpView.renderAsync.call(tmpView, tmpRenderableHash, tmpRenderDestinationAddress, tmpTemplateDataAddress, fNext);\n\t\t\t});\n\n\t\ttmpRenderAnticipate.anticipate(this.onAfterRenderAsync.bind(this));\n\n\t\treturn tmpRenderAnticipate.wait(tmpCallback);\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tonAfterRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} onAfterRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\tonAfterRenderAsync(fCallback)\n\t{\n\t\tthis.onAfterRender();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\trenderMainViewport()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderMainViewport:`);\n\t\t}\n\n\t\treturn this.render();\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\trenderMainViewportAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow APPLICATION [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderMainViewportAsync:`);\n\t\t}\n\n\t\treturn this.renderAsync(fCallback);\n\t}\n\t/**\n\t * @return {void}\n\t */\n\trenderAutoViews()\n\t{\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning renderAutoViews...`);\n\t\t}\n\t\t// Now walk through any loaded views and sort them by the AutoRender ordinal\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t// Sort the views by their priority\n\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\ttmpLoadedViews.sort((a, b) =>\n\t\t{\n\t\t\treturn this.pict.views[a].options.AutoRenderOrdinal - this.pict.views[b].options.AutoRenderOrdinal;\n\t\t});\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoRender)\n\t\t\t{\n\t\t\t\ttmpView.render();\n\t\t\t}\n\t\t}\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync complete.`);\n\t\t}\n\t}\n\t/**\n\t * @param {(error?: Error) => void} fCallback\n\t */\n\trenderAutoViewsAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\tfalse;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync Auto Callback Error: ${pError}`, pError)\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} beginning renderAutoViewsAsync...`);\n\t\t}\n\n\t\t// Now walk through any loaded views and sort them by the AutoRender ordinal\n\t\t// TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.\n\t\tlet tmpLoadedViews = Object.keys(this.pict.views);\n\t\t// Sort the views by their priority\n\t\t// If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff\n\t\ttmpLoadedViews.sort((a, b) =>\n\t\t{\n\t\t\treturn this.pict.views[a].options.AutoRenderOrdinal - this.pict.views[b].options.AutoRenderOrdinal;\n\t\t});\n\t\tfor (let i = 0; i < tmpLoadedViews.length; i++)\n\t\t{\n\t\t\tlet tmpView = this.pict.views[tmpLoadedViews[i]];\n\t\t\tif (tmpView.options.AutoRender)\n\t\t\t{\n\t\t\t\ttmpAnticipate.anticipate(tmpView.renderAsync.bind(tmpView));\n\t\t\t}\n\t\t}\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tthis.lastAutoRenderTimestamp = this.fable.log.getTimeStamp();\n\t\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictApp [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAutoViewsAsync complete.`);\n\t\t\t\t}\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * @return {boolean}\n\t */\n\tget isPictApplication()\n\t{\n\t\treturn true;\n\t}\n}\n\nmodule.exports = PictApplication;\n","module.exports={\n \"name\": \"pict-provider\",\n \"version\": \"1.0.12\",\n \"description\": \"Pict Provider Base Class\",\n \"main\": \"source/Pict-Provider.js\",\n \"scripts\": {\n \"start\": \"node source/Pict-Provider.js\",\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-provider-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-provider-dev -p 24125:8080 -p 30027:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-provider\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-provider-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-provider-dev /bin/bash\",\n \"lint\": \"eslint source/**\",\n \"types\": \"tsc -p .\"\n },\n \"types\": \"types/source/Pict-Provider.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-provider.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-provider/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-provider#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.1\",\n \"eslint\": \"^9.39.1\",\n \"pict\": \"^1.0.351\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"dependencies\": {\n \"fable-serviceproviderbase\": \"^3.0.19\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n }\n}\n","const libFableServiceBase = require('fable-serviceproviderbase');\n\nconst libPackage = require('../package.json');\n\nconst defaultPictProviderSettings = (\n\t{\n\t\tProviderIdentifier: false,\n\n\t\t// If this is set to true, when the App initializes this will.\n\t\t// After the App initializes, initialize will be called as soon as it's added.\n\t\tAutoInitialize: true,\n\t\tAutoInitializeOrdinal: 0,\n\n\t\tAutoLoadDataWithApp: true,\n\t\tAutoLoadDataOrdinal: 0,\n\n\t\tAutoSolveWithApp: true,\n\t\tAutoSolveOrdinal: 0,\n\n\t\tManifests: {},\n\n\t\tTemplates: []\n\t});\n\nclass PictProvider extends libFableServiceBase\n{\n\t/**\n\t * @param {import('fable')} pFable - The Fable instance.\n\t * @param {Record<string, any>} [pOptions] - The options for the provider.\n\t * @param {string} [pServiceHash] - The service hash for the provider.\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t// Intersect default options, parent constructor, service information\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictProviderSettings)), pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\t/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */\n\t\tthis.fable;\n\t\t/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */\n\t\tthis.pict;\n\t\t/** @type {any} */\n\t\tthis.log;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.options;\n\t\t/** @type {string} */\n\t\tthis.UUID;\n\t\t/** @type {string} */\n\t\tthis.Hash;\n\n\t\tif (!this.options.ProviderIdentifier)\n\t\t{\n\t\t\tthis.options.ProviderIdentifier = `AutoProviderID-${this.fable.getUUID()}`;\n\t\t}\n\n\t\tthis.serviceType = 'PictProvider';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\n\t\t// Convenience and consistency naming\n\t\tthis.pict = this.fable;\n\n\t\t// Wire in the essential Pict application state\n\t\t/** @type {Record<string, any>} */\n\t\tthis.AppData = this.pict.AppData;\n\t\t/** @type {Record<string, any>} */\n\t\tthis.Bundle = this.pict.Bundle;\n\n\t\tthis.initializeTimestamp = false;\n\t\tthis.lastSolvedTimestamp = false;\n\n\t\tfor (let i = 0; i < this.options.Templates.length; i++)\n\t\t{\n\t\t\tlet tmpDefaultTemplate = this.options.Templates[i];\n\n\t\t\tif (!tmpDefaultTemplate.hasOwnProperty('Postfix') || !tmpDefaultTemplate.hasOwnProperty('Template'))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} could not load Default Template ${i} in the options array.`, tmpDefaultTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpDefaultTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpDefaultTemplate.Source = `PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix, tmpDefaultTemplate.Postfix, tmpDefaultTemplate.Template, tmpDefaultTemplate.Source);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialization */\n\t/* -------------------------------------------------------------------------- */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-pinitialization.\n\t *\n\t * @return {void}\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\tonInitialize()\n\t{\n\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow PROVIDER [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\t\t\tthis.onInitialize();\n\t\t\tthis.onAfterInitialize();\n\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow PROVIDER [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initializeAsync:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.info(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} beginning initialization...`);\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialization failed: ${pError.message || pError}`, { Stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\telse if (this.pict.LogNoisiness > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.info(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fCallback();\n\t\t\t\t})\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn fCallback();\n\t\t}\n\t}\n\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.\n\t *\n\t * @return {void}\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\tonPreRender()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onPreRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-render.\n\t *\n\t * @return {void}\n\t */\n\tonPreRenderAsync(fCallback)\n\t{\n\t\tthis.onPreRender();\n\t\treturn fCallback();\n\t}\n\n\trender()\n\t{\n\t\treturn this.onPreRender();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after render.\n\t *\n\t * @return {void}\n\t */\n\trenderAsync(fCallback)\n\t{\n\t\tthis.onPreRender();\n\t\treturn fCallback();\n\t}\n\n\tonPreSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onPreSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after pre-solve.\n\t *\n\t * @return {void}\n\t */\n\tonPreSolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\tsolve()\n\t{\n\t\treturn this.onPreSolve();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after solve.\n\t *\n\t * @return {void}\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tthis.onPreSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.\n\t */\n\tonBeforeLoadDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Hook to allow the provider to load data during application data load.\n\t *\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.\n\t */\n\tonLoadDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onLoadDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.\n\t */\n\tonAfterLoadDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.\n\t *\n\t * @return {void}\n\t */\n\tonBeforeSaveDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Hook to allow the provider to load data during application data load.\n\t *\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.\n\t *\n\t * @return {void}\n\t */\n\tonSaveDataAsync(fCallback)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictProvider [${this.UUID}]::[${this.Hash}] ${this.options.ProviderIdentifier} onSaveDataAsync:`);\n\t\t}\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.\n\t *\n\t * @return {void}\n\t */\n\tonAfterSaveDataAsync(fCallback)\n\t{\n\t\treturn fCallback();\n\t}\n}\n\nmodule.exports = PictProvider;\n","module.exports = (\n{\n\t\"RenderOnLoad\": true,\n\n\t\"DefaultRenderable\": \"Histogram-Wrap\",\n\t\"DefaultDestinationAddress\": \"#Histogram-Container-Div\",\n\n\t\"Templates\":\n\t[\n\t\t{\n\t\t\t\"Hash\": \"Histogram-Container\",\n\t\t\t\"Template\": \"<!-- Histogram Container Rendering Soon -->\"\n\t\t}\n\t],\n\n\t\"Renderables\":\n\t[\n\t\t{\n\t\t\t\"RenderableHash\": \"Histogram-Wrap\",\n\t\t\t\"TemplateHash\": \"Histogram-Container\",\n\t\t\t\"DestinationAddress\": \"#Histogram-Container-Div\"\n\t\t}\n\t],\n\n\t\"TargetElementAddress\": \"#Histogram-Container-Div\",\n\n\t// --- Data Configuration ---\n\n\t// Address in AppData (or other Pict address space) for the histogram bins\n\t// Expected format: Array of objects with at least { Label, Value } properties\n\t// e.g. [{ Label: \"2020\", Value: 15 }, { Label: \"2021\", Value: 42 }]\n\t\"DataAddress\": false,\n\n\t// Alternatively, provide bins directly (used if DataAddress is not set)\n\t\"Bins\": [],\n\n\t// Property names within each bin object\n\t\"LabelProperty\": \"Label\",\n\t\"ValueProperty\": \"Value\",\n\n\t// --- Layout Configuration ---\n\n\t// \"vertical\" = bars grow upward; \"horizontal\" = bars grow rightward\n\t\"Orientation\": \"vertical\",\n\n\t// The rendering mode: \"browser\", \"consoleui\", or \"cli\"\n\t// \"browser\" renders HTML/CSS/SVG; \"consoleui\" renders via blessed widgets;\n\t// \"cli\" renders ANSI text to stdout\n\t\"RenderMode\": \"browser\",\n\n\t// Maximum height in pixels (browser vertical) or characters (cli/consoleui)\n\t\"MaxBarSize\": 200,\n\n\t// Bar thickness in pixels (browser) or characters (cli/consoleui)\n\t\"BarThickness\": 30,\n\n\t// Gap between bars in pixels (browser) or characters (cli/consoleui)\n\t\"BarGap\": 4,\n\n\t// Whether to show value labels on/above bars\n\t\"ShowValues\": true,\n\n\t// Whether to show bin labels (x-axis for vertical, y-axis for horizontal)\n\t\"ShowLabels\": true,\n\n\t// Color of the bars (CSS color for browser, ANSI color name for cli/consoleui)\n\t\"BarColor\": \"#4A90D9\",\n\n\t// Color of selected bars\n\t\"SelectedBarColor\": \"#2ECC71\",\n\n\t// Color of bars in the selection range\n\t\"SelectionRangeColor\": \"#85C1E9\",\n\n\t// --- Selection Configuration ---\n\n\t// Enable selection mode\n\t\"Selectable\": false,\n\n\t// Selection mode: \"single\", \"multiple\", \"range\"\n\t// \"single\" - click to select one bar\n\t// \"multiple\" - click to toggle individual bars\n\t// \"range\" - drag sliders to select a contiguous range of bins\n\t\"SelectionMode\": \"range\",\n\n\t// Address in AppData to write selection state\n\t// Will contain { SelectedIndices: [], RangeStart: N, RangeEnd: N } or similar\n\t\"SelectionDataAddress\": false,\n\n\t// Initial selection (array of indices or { Start, End } for range mode)\n\t\"InitialSelection\": null,\n\n\t// --- CLI/ConsoleUI Configuration ---\n\n\t// Characters used for rendering in text mode\n\t\"BarCharacter\": \"\\u2588\",\n\t\"BarPartialCharacters\": [\" \", \"\\u2581\", \"\\u2582\", \"\\u2583\", \"\\u2584\", \"\\u2585\", \"\\u2586\", \"\\u2587\", \"\\u2588\"],\n\t\"EmptyCharacter\": \" \",\n\t\"SliderCharacter\": \"\\u2502\",\n\t\"SliderHandleCharacter\": \"\\u25C6\",\n\n\t// Width of the histogram in characters (cli/consoleui)\n\t\"TextWidth\": 60,\n\n\t// Height of the histogram in characters (cli/consoleui vertical)\n\t\"TextHeight\": 15,\n\n\t// --- CSS ---\n\t\"CSS\": `.pict-histogram-container\n{\n\tdisplay: inline-block;\n\tposition: relative;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n\tfont-size: 12px;\n\tuser-select: none;\n}\n.pict-histogram-chart\n{\n\tdisplay: flex;\n\talign-items: flex-end;\n\tposition: relative;\n}\n.pict-histogram-container.pict-histogram-horizontal\n{\n\tdisplay: inline-flex;\n\tflex-direction: row;\n\talign-items: stretch;\n}\n.pict-histogram-chart.pict-histogram-horizontal\n{\n\tflex-direction: column;\n\talign-items: flex-start;\n}\n.pict-histogram-bar-group\n{\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tcursor: default;\n\tflex-shrink: 0;\n}\n.pict-histogram-horizontal .pict-histogram-bar-group\n{\n\tflex-direction: row;\n\talign-items: center;\n}\n.pict-histogram-bar\n{\n\ttransition: background-color 0.15s ease, height 0.2s ease, width 0.2s ease;\n\tborder-radius: 2px 2px 0 0;\n\tmin-width: 1px;\n\tmin-height: 1px;\n}\n.pict-histogram-horizontal .pict-histogram-bar\n{\n\tborder-radius: 0 2px 2px 0;\n}\n.pict-histogram-bar.pict-histogram-selectable\n{\n\tcursor: pointer;\n}\n.pict-histogram-bar.pict-histogram-selectable:hover\n{\n\topacity: 0.8;\n}\n.pict-histogram-bar.pict-histogram-selected\n{\n\tbox-shadow: 0 0 0 2px rgba(46, 204, 113, 0.4);\n}\n.pict-histogram-bar.pict-histogram-in-range\n{\n\topacity: 0.9;\n}\n.pict-histogram-value-label\n{\n\ttext-align: center;\n\tcolor: #666;\n\tfont-size: 11px;\n\tpadding: 2px 0;\n\twhite-space: nowrap;\n}\n.pict-histogram-horizontal .pict-histogram-value-label\n{\n\tpadding: 0 4px;\n}\n.pict-histogram-bin-label\n{\n\ttext-align: center;\n\tcolor: #333;\n\tfont-size: 11px;\n\tpadding: 4px 2px 0 2px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n.pict-histogram-horizontal .pict-histogram-bin-label\n{\n\tpadding: 0 4px 0 0;\n\ttext-align: right;\n\tmin-width: 40px;\n}\n.pict-histogram-range-slider-container\n{\n\tposition: relative;\n\twidth: 100%;\n\theight: 24px;\n\tmargin-top: 4px;\n}\n.pict-histogram-horizontal .pict-histogram-range-slider-container\n{\n\twidth: 24px;\n\theight: auto;\n\talign-self: stretch;\n\tmargin-top: 0;\n\tmargin-left: 4px;\n}\n.pict-histogram-range-track\n{\n\tposition: absolute;\n\ttop: 10px;\n\tleft: 0;\n\tright: 0;\n\theight: 4px;\n\tbackground: #E0E0E0;\n\tborder-radius: 2px;\n}\n.pict-histogram-horizontal .pict-histogram-range-track\n{\n\ttop: 0;\n\tleft: 10px;\n\tright: auto;\n\tbottom: 0;\n\twidth: 4px;\n\theight: auto;\n}\n.pict-histogram-range-fill\n{\n\tposition: absolute;\n\ttop: 10px;\n\theight: 4px;\n\tbackground: #4A90D9;\n\tborder-radius: 2px;\n}\n.pict-histogram-horizontal .pict-histogram-range-fill\n{\n\ttop: auto;\n\tleft: 10px;\n\twidth: 4px;\n\theight: auto;\n}\n.pict-histogram-range-handle\n{\n\tposition: absolute;\n\ttop: 4px;\n\twidth: 16px;\n\theight: 16px;\n\tbackground: #fff;\n\tborder: 2px solid #4A90D9;\n\tborder-radius: 50%;\n\tcursor: grab;\n\tz-index: 2;\n\ttransform: translateX(-50%);\n}\n.pict-histogram-horizontal .pict-histogram-range-handle\n{\n\ttop: auto;\n\tleft: 4px;\n\ttransform: translateY(-50%);\n}\n.pict-histogram-range-handle:active\n{\n\tcursor: grabbing;\n\tbackground: #4A90D9;\n}\n.pict-histogram-range-handle:active,\n.pict-histogram-range-handle:focus\n{\n\tbox-shadow: 0 0 0 3px rgba(74, 144, 217, 0.3);\n\toutline: none;\n}\n`\n});\n","/**\n * Pict Section Histogram\n *\n * A histogram visualization section for the Pict MVC framework.\n *\n * Supports:\n * - Vertical and horizontal orientation\n * - Three render modes: browser (HTML/CSS), consoleui (blessed), cli (ANSI)\n * - Interactive selection: single click, multi-select, or range slider\n * - Data binding via Pict AppData addresses\n *\n * @module pict-section-histogram\n */\n\nconst libPictViewClass = require('pict-view');\nconst _DefaultConfiguration = require('./Pict-Section-Histogram-DefaultConfiguration.js');\n\nconst libRendererBrowser = require('./renderers/Pict-Histogram-Renderer-Browser.js');\nconst libRendererConsoleUI = require('./renderers/Pict-Histogram-Renderer-ConsoleUI.js');\nconst libRendererCLI = require('./renderers/Pict-Histogram-Renderer-CLI.js');\n\nclass PictSectionHistogram extends libPictViewClass\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tlet tmpOptions = Object.assign({}, _DefaultConfiguration, pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\n\t\tthis.initialRenderComplete = false;\n\n\t\t// --- Selection State ---\n\n\t\t// Set of selected bin indices (for \"single\" and \"multiple\" modes)\n\t\tthis._selectedIndices = new Set();\n\n\t\t// Range bounds (for \"range\" mode)\n\t\tthis._selectionRangeStart = 0;\n\t\tthis._selectionRangeEnd = 0;\n\n\t\t// Resolve the renderer for the configured mode\n\t\tthis._renderer = this._resolveRenderer();\n\n\t\t// Apply initial selection if provided\n\t\tthis._applyInitialSelection();\n\t}\n\n\t/**\n\t * Set up the initial selection state from options.\n\t */\n\t_applyInitialSelection()\n\t{\n\t\tif (this.options.InitialSelection)\n\t\t{\n\t\t\tthis.setSelection(this.options.InitialSelection);\n\t\t}\n\t\telse if (this.options.Selectable && this.options.SelectionMode === 'range')\n\t\t{\n\t\t\t// Default: select all bins\n\t\t\tlet tmpBins = this.getBins();\n\t\t\tthis._selectionRangeStart = 0;\n\t\t\tthis._selectionRangeEnd = Math.max(0, tmpBins.length - 1);\n\t\t\tthis._syncSelectionFromRange();\n\t\t}\n\t}\n\n\t/**\n\t * Pick the renderer module based on RenderMode option.\n\t *\n\t * @returns {object} The renderer module { render, wireEvents }\n\t */\n\t_resolveRenderer()\n\t{\n\t\tswitch (this.options.RenderMode)\n\t\t{\n\t\t\tcase 'consoleui':\n\t\t\t\treturn libRendererConsoleUI;\n\t\t\tcase 'cli':\n\t\t\t\treturn libRendererCLI;\n\t\t\tcase 'browser':\n\t\t\tdefault:\n\t\t\t\treturn libRendererBrowser;\n\t\t}\n\t}\n\n\t// --- Data Access ---\n\n\t/**\n\t * Get the current bin data array.\n\t *\n\t * Reads from the configured DataAddress in AppData, falling back to\n\t * the static Bins option.\n\t *\n\t * @returns {Array} Array of bin objects\n\t */\n\tgetBins()\n\t{\n\t\tif (this.options.DataAddress)\n\t\t{\n\t\t\tconst tmpAddressSpace =\n\t\t\t{\n\t\t\t\tFable: this.fable,\n\t\t\t\tPict: this.fable,\n\t\t\t\tAppData: this.AppData,\n\t\t\t\tBundle: this.Bundle,\n\t\t\t\tOptions: this.options\n\t\t\t};\n\t\t\tlet tmpData = this.fable.manifest.getValueByHash(tmpAddressSpace, this.options.DataAddress);\n\t\t\tif (Array.isArray(tmpData))\n\t\t\t{\n\t\t\t\treturn tmpData;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis.log.warn(`PICT-Histogram DataAddress [${this.options.DataAddress}] did not return an array.`);\n\t\t\t}\n\t\t}\n\n\t\treturn this.options.Bins || [];\n\t}\n\n\t/**\n\t * Set the bins programmatically (updates the Bins option).\n\t *\n\t * @param {Array} pBins - Array of bin objects { Label, Value, ... }\n\t */\n\tsetBins(pBins)\n\t{\n\t\tif (!Array.isArray(pBins))\n\t\t{\n\t\t\tthis.log.warn('PICT-Histogram setBins requires an array.');\n\t\t\treturn;\n\t\t}\n\t\tthis.options.Bins = pBins;\n\n\t\t// If we also have a DataAddress, write through\n\t\tif (this.options.DataAddress)\n\t\t{\n\t\t\tconst tmpAddressSpace =\n\t\t\t{\n\t\t\t\tFable: this.fable,\n\t\t\t\tPict: this.fable,\n\t\t\t\tAppData: this.AppData,\n\t\t\t\tBundle: this.Bundle,\n\t\t\t\tOptions: this.options\n\t\t\t};\n\t\t\tthis.fable.manifest.setValueByHash(tmpAddressSpace, this.options.DataAddress, pBins);\n\t\t}\n\t}\n\n\t// --- Selection Logic ---\n\n\t/**\n\t * Check whether a bin index is currently selected.\n\t *\n\t * @param {number} pIndex\n\t * @returns {boolean}\n\t */\n\tisIndexSelected(pIndex)\n\t{\n\t\tif (!this.options.Selectable)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\treturn (pIndex === this._selectionRangeStart || pIndex === this._selectionRangeEnd);\n\t\t}\n\n\t\treturn this._selectedIndices.has(pIndex);\n\t}\n\n\t/**\n\t * Check whether a bin index falls within the current range selection\n\t * (but is not one of the range endpoints).\n\t *\n\t * @param {number} pIndex\n\t * @returns {boolean}\n\t */\n\tisIndexInRange(pIndex)\n\t{\n\t\tif (!this.options.Selectable || this.options.SelectionMode !== 'range')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn (pIndex > this._selectionRangeStart && pIndex < this._selectionRangeEnd);\n\t}\n\n\t/**\n\t * Get the current selection state.\n\t *\n\t * @returns {object} Selection descriptor\n\t */\n\tgetSelection()\n\t{\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\tlet tmpBins = this.getBins();\n\t\t\tlet tmpIndices = [];\n\t\t\tfor (let i = this._selectionRangeStart; i <= this._selectionRangeEnd; i++)\n\t\t\t{\n\t\t\t\ttmpIndices.push(i);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tMode: 'range',\n\t\t\t\tRangeStart: this._selectionRangeStart,\n\t\t\t\tRangeEnd: this._selectionRangeEnd,\n\t\t\t\tSelectedIndices: tmpIndices,\n\t\t\t\tStartLabel: (tmpBins[this._selectionRangeStart] || {})[this.options.LabelProperty],\n\t\t\t\tEndLabel: (tmpBins[this._selectionRangeEnd] || {})[this.options.LabelProperty]\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn {\n\t\t\t\tMode: this.options.SelectionMode,\n\t\t\t\tSelectedIndices: Array.from(this._selectedIndices).sort((a, b) => a - b)\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Programmatically set the selection.\n\t *\n\t * @param {object|Array} pSelection - For range: { Start, End }; for single/multiple: array of indices\n\t */\n\tsetSelection(pSelection)\n\t{\n\t\tif (this.options.SelectionMode === 'range')\n\t\t{\n\t\t\tif (pSelection && typeof (pSelection.Start) === 'number' && typeof (pSelection.End) === 'number')\n\t\t\t{\n\t\t\t\tthis._selectionRangeStart = pSelection.Start;\n\t\t\t\tthis._selectionRangeEnd = pSelection.End;\n\t\t\t\tthis._syncSelectionFromRange();\n\t\t\t}\n\t\t}\n\t\telse if (Array.isArray(pSelection))\n\t\t{\n\t\t\tthis._selectedIndices = new Set(pSelection);\n\t\t}\n\n\t\tthis._writeSelectionToAddress();\n\t}\n\n\t/**\n\t * Handle a bar click in single or multiple selection mode.\n\t *\n\t * @param {number} pIndex - The clicked bin index\n\t */\n\thandleBarClick(pIndex)\n\t{\n\t\tif (this.options.SelectionMode === 'single')\n\t\t{\n\t\t\tthis._selectedIndices.clear();\n\t\t\tthis._selectedIndices.add(pIndex);\n\t\t}\n\t\telse if (this.options.SelectionMode === 'multiple')\n\t\t{\n\t\t\tif (this._selectedIndices.has(pIndex))\n\t\t\t{\n\t\t\t\tthis._selectedIndices.delete(pIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis._selectedIndices.add(pIndex);\n\t\t\t}\n\t\t}\n\n\t\tthis._writeSelectionToAddress();\n\t\tthis.onSelectionChange(this.getSelection());\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Handle a bar click in range mode — moves the nearest handle.\n\t *\n\t * @param {number} pIndex - The clicked bin index\n\t */\n\thandleRangeBarClick(pIndex)\n\t{\n\t\tlet tmpDistStart = Math.abs(pIndex - this._selectionRangeStart);\n\t\tlet tmpDistEnd = Math.abs(pIndex - this._selectionRangeEnd);\n\n\t\tif (tmpDistStart <= tmpDistEnd)\n\t\t{\n\t\t\tthis._selectionRangeStart = Math.min(pIndex, this._selectionRangeEnd);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis._selectionRangeEnd = Math.max(pIndex, this._selectionRangeStart);\n\t\t}\n\n\t\tthis._syncSelectionFromRange();\n\t\tthis._writeSelectionToAddress();\n\t\tthis.onSelectionChange(this.getSelection());\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Sync _selectedIndices from the range bounds (so getSelection is consistent).\n\t */\n\t_syncSelectionFromRange()\n\t{\n\t\tthis._selectedIndices.clear();\n\t\tfor (let i = this._selectionRangeStart; i <= this._selectionRangeEnd; i++)\n\t\t{\n\t\t\tthis._selectedIndices.add(i);\n\t\t}\n\t}\n\n\t/**\n\t * Write the current selection state to the configured SelectionDataAddress.\n\t */\n\t_writeSelectionToAddress()\n\t{\n\t\tif (!this.options.SelectionDataAddress)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tconst tmpAddressSpace =\n\t\t{\n\t\t\tFable: this.fable,\n\t\t\tPict: this.fable,\n\t\t\tAppData: this.AppData,\n\t\t\tBundle: this.Bundle,\n\t\t\tOptions: this.options\n\t\t};\n\n\t\tthis.fable.manifest.setValueByHash(tmpAddressSpace, this.options.SelectionDataAddress, this.getSelection());\n\t}\n\n\t/**\n\t * Hook for subclasses or consumers to react to selection changes.\n\t *\n\t * @param {object} pSelection - The new selection state\n\t */\n\tonSelectionChange(pSelection)\n\t{\n\t\t// Override in subclass or assign externally\n\t}\n\n\t// --- Lifecycle Hooks ---\n\n\tonBeforeInitialize()\n\t{\n\t\tsuper.onBeforeInitialize();\n\t\treturn super.onBeforeInitialize();\n\t}\n\n\tonAfterRender(pRenderable)\n\t{\n\t\t// Inject CSS\n\t\tthis.pict.CSSMap.injectCSS();\n\n\t\tif (!this.initialRenderComplete)\n\t\t{\n\t\t\tthis.onAfterInitialRender();\n\t\t\tthis.initialRenderComplete = true;\n\t\t}\n\n\t\treturn super.onAfterRender(pRenderable);\n\t}\n\n\tonAfterInitialRender()\n\t{\n\t\tthis.renderHistogram();\n\t}\n\n\t/**\n\t * Render the histogram using the active renderer and wire events.\n\t */\n\trenderHistogram()\n\t{\n\t\t// Ensure CSS is injected (covers both lifecycle and direct calls)\n\t\tif (this.pict.CSSMap)\n\t\t{\n\t\t\tthis.pict.CSSMap.injectCSS();\n\t\t}\n\t\tthis._renderer.render(this);\n\t\tthis._renderer.wireEvents(this);\n\t\tthis.initialRenderComplete = true;\n\t}\n\n\t// --- Data Marshaling ---\n\n\tmarshalToView()\n\t{\n\t\tsuper.marshalToView();\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\tmarshalFromView()\n\t{\n\t\tsuper.marshalFromView();\n\t\tthis._writeSelectionToAddress();\n\t}\n\n\t// --- Public API ---\n\n\t/**\n\t * Change the orientation and re-render.\n\t *\n\t * @param {string} pOrientation - \"vertical\" or \"horizontal\"\n\t */\n\tsetOrientation(pOrientation)\n\t{\n\t\tif (pOrientation !== 'vertical' && pOrientation !== 'horizontal')\n\t\t{\n\t\t\tthis.log.warn(`PICT-Histogram invalid orientation: ${pOrientation}`);\n\t\t\treturn;\n\t\t}\n\t\tthis.options.Orientation = pOrientation;\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\t/**\n\t * Change the render mode and re-render.\n\t *\n\t * @param {string} pRenderMode - \"browser\", \"consoleui\", or \"cli\"\n\t */\n\tsetRenderMode(pRenderMode)\n\t{\n\t\tthis.options.RenderMode = pRenderMode;\n\t\tthis._renderer = this._resolveRenderer();\n\t\tif (this.initialRenderComplete)\n\t\t{\n\t\t\tthis.renderHistogram();\n\t\t}\n\t}\n\n\t/**\n\t * Convenience: get the text representation (useful for CLI/consoleui).\n\t *\n\t * @returns {string}\n\t */\n\ttoText()\n\t{\n\t\tif (this.options.Orientation === 'vertical')\n\t\t{\n\t\t\treturn libRendererConsoleUI.renderVertical(this);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn libRendererConsoleUI.renderHorizontal(this);\n\t\t}\n\t}\n}\n\nmodule.exports = PictSectionHistogram;\n\nmodule.exports.default_configuration = _DefaultConfiguration;\nmodule.exports.renderers = {\n\tbrowser: libRendererBrowser,\n\tconsoleui: libRendererConsoleUI,\n\tcli: libRendererCLI\n};\n","/**\n * Browser renderer for pict-section-histogram.\n *\n * Renders the histogram as HTML/CSS elements using the Pict ContentAssignment\n * pipeline. Also wires up interactive selection (click, drag-slider) via\n * DOM event listeners.\n *\n * @module Pict-Histogram-Renderer-Browser\n */\n\n/**\n * Build the HTML string for a single bar group (bar + optional labels).\n *\n * @param {object} pBin - The bin data { Label, Value, ... }\n * @param {number} pIndex - Index of the bin\n * @param {number} pBarSize - Computed bar size in pixels\n * @param {object} pOptions - View options\n * @param {boolean} pIsSelected - Whether this bin is selected\n * @param {boolean} pInRange - Whether this bin is inside the range selection\n * @param {number} pLabelWidth - Fixed label width in pixels (horizontal mode)\n * @returns {string} HTML fragment\n */\nfunction buildBarGroupHTML(pBin, pIndex, pBarSize, pOptions, pIsSelected, pInRange, pLabelWidth)\n{\n\tlet tmpLabel = pBin[pOptions.LabelProperty] || '';\n\tlet tmpValue = pBin[pOptions.ValueProperty] || 0;\n\tlet tmpVertical = (pOptions.Orientation === 'vertical');\n\tlet tmpBarColor = pIsSelected ? pOptions.SelectedBarColor\n\t\t: pInRange ? pOptions.SelectionRangeColor\n\t\t: pOptions.BarColor;\n\n\tlet tmpSelectableClass = pOptions.Selectable ? ' pict-histogram-selectable' : '';\n\tlet tmpSelectedClass = pIsSelected ? ' pict-histogram-selected' : '';\n\tlet tmpInRangeClass = pInRange ? ' pict-histogram-in-range' : '';\n\n\tlet tmpBarStyle = '';\n\tif (tmpVertical)\n\t{\n\t\ttmpBarStyle = `height:${pBarSize}px;width:${pOptions.BarThickness}px;background-color:${tmpBarColor};`;\n\t}\n\telse\n\t{\n\t\ttmpBarStyle = `width:${pBarSize}px;height:${pOptions.BarThickness}px;background-color:${tmpBarColor};`;\n\t}\n\n\tlet tmpGroupWidth = pOptions.BarThickness + pOptions.BarGap;\n\tlet tmpGroupStyle = '';\n\tif (tmpVertical)\n\t{\n\t\ttmpGroupStyle = `margin:0 ${pOptions.BarGap / 2}px;width:${tmpGroupWidth}px;`;\n\t}\n\telse\n\t{\n\t\ttmpGroupStyle = `margin:${pOptions.BarGap / 2}px 0;`;\n\t}\n\n\tlet tmpHTML = `<div class=\"pict-histogram-bar-group\" style=\"${tmpGroupStyle}\" data-histogram-index=\"${pIndex}\">`;\n\n\tif (tmpVertical)\n\t{\n\t\t// Value label above bar\n\t\tif (pOptions.ShowValues)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-value-label\" style=\"width:${tmpGroupWidth}px;\">${tmpValue}</div>`;\n\t\t}\n\t\t// Bar\n\t\ttmpHTML += `<div class=\"pict-histogram-bar${tmpSelectableClass}${tmpSelectedClass}${tmpInRangeClass}\" style=\"${tmpBarStyle}\" data-histogram-index=\"${pIndex}\"></div>`;\n\t\t// Bin label below bar\n\t\tif (pOptions.ShowLabels)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-bin-label\" style=\"width:${tmpGroupWidth}px;\">${tmpLabel}</div>`;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Bin label to the left (fixed width so bars align)\n\t\tif (pOptions.ShowLabels)\n\t\t{\n\t\t\tlet tmpLabelStyle = pLabelWidth ? `width:${pLabelWidth}px;min-width:${pLabelWidth}px;` : '';\n\t\t\ttmpHTML += `<div class=\"pict-histogram-bin-label\" style=\"${tmpLabelStyle}\">${tmpLabel}</div>`;\n\t\t}\n\t\t// Bar\n\t\ttmpHTML += `<div class=\"pict-histogram-bar${tmpSelectableClass}${tmpSelectedClass}${tmpInRangeClass}\" style=\"${tmpBarStyle}\" data-histogram-index=\"${pIndex}\"></div>`;\n\t\t// Value label to the right\n\t\tif (pOptions.ShowValues)\n\t\t{\n\t\t\ttmpHTML += `<div class=\"pict-histogram-value-label\">${tmpValue}</div>`;\n\t\t}\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Build the HTML for the range-slider overlay (used in \"range\" selection mode).\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} HTML fragment\n */\nfunction buildRangeSliderHTML(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '';\n\t}\n\n\tlet tmpRangeStart = pView._selectionRangeStart;\n\tlet tmpRangeEnd = pView._selectionRangeEnd;\n\tlet tmpMax = tmpBins.length - 1;\n\n\t// Calculate percentage positions for the handles\n\tlet tmpStartPct = (tmpMax > 0) ? ((tmpRangeStart / tmpMax) * 100) : 0;\n\tlet tmpEndPct = (tmpMax > 0) ? ((tmpRangeEnd / tmpMax) * 100) : 100;\n\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\n\tlet tmpHTML = '<div class=\"pict-histogram-range-slider-container\">';\n\ttmpHTML += '<div class=\"pict-histogram-range-track\"></div>';\n\n\tif (tmpVertical)\n\t{\n\t\ttmpHTML += `<div class=\"pict-histogram-range-fill\" style=\"left:${tmpStartPct}%;right:${100 - tmpEndPct}%;\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-start\" tabindex=\"0\" style=\"left:${tmpStartPct}%;\" data-handle=\"start\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-end\" tabindex=\"0\" style=\"left:${tmpEndPct}%;\" data-handle=\"end\"></div>`;\n\t}\n\telse\n\t{\n\t\ttmpHTML += `<div class=\"pict-histogram-range-fill\" style=\"top:${tmpStartPct}%;bottom:${100 - tmpEndPct}%;\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-start\" tabindex=\"0\" style=\"top:${tmpStartPct}%;\" data-handle=\"start\"></div>`;\n\t\ttmpHTML += `<div class=\"pict-histogram-range-handle pict-histogram-range-handle-end\" tabindex=\"0\" style=\"top:${tmpEndPct}%;\" data-handle=\"end\"></div>`;\n\t}\n\n\ttmpHTML += '</div>';\n\treturn tmpHTML;\n}\n\n/**\n * Render the full histogram into the target element.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\tpView.services.ContentAssignment.assignContent(\n\t\t\tpView.options.TargetElementAddress,\n\t\t\t'<div class=\"pict-histogram-container\"><em>No histogram data</em></div>'\n\t\t);\n\t\treturn;\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][pView.options.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\tlet tmpOrientationClass = tmpVertical ? 'pict-histogram-vertical' : 'pict-histogram-horizontal';\n\n\t// For horizontal mode, measure the longest label so all labels share the same width\n\tlet tmpLabelWidth = 0;\n\tif (!tmpVertical && pView.options.ShowLabels)\n\t{\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][pView.options.LabelProperty] || '');\n\t\t\t// Approximate character width at 11px font: ~6.5px per character\n\t\t\tlet tmpEstWidth = tmpLabel.length * 6.5 + 8;\n\t\t\tif (tmpEstWidth > tmpLabelWidth)\n\t\t\t{\n\t\t\t\ttmpLabelWidth = tmpEstWidth;\n\t\t\t}\n\t\t}\n\t\ttmpLabelWidth = Math.max(tmpLabelWidth, 40);\n\t}\n\n\tlet tmpHTML = `<div class=\"pict-histogram-container ${tmpOrientationClass}\">`;\n\ttmpHTML += `<div class=\"pict-histogram-chart ${tmpOrientationClass}\">`;\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][pView.options.ValueProperty] || 0;\n\t\tlet tmpBarSize = Math.round((tmpVal / tmpMaxValue) * pView.options.MaxBarSize);\n\t\tif (tmpVal > 0 && tmpBarSize < 1)\n\t\t{\n\t\t\ttmpBarSize = 1;\n\t\t}\n\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\n\t\ttmpHTML += buildBarGroupHTML(tmpBins[i], i, tmpBarSize, pView.options, tmpIsSelected, tmpInRange, tmpLabelWidth);\n\t}\n\n\ttmpHTML += '</div>';\n\n\t// Range slider for \"range\" selection mode\n\tif (pView.options.Selectable && pView.options.SelectionMode === 'range')\n\t{\n\t\ttmpHTML += buildRangeSliderHTML(pView);\n\t}\n\n\ttmpHTML += '</div>';\n\n\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpHTML);\n}\n\n/**\n * Wire up DOM event listeners for interactivity (click selection, range drag).\n *\n * @param {object} pView - The histogram view instance\n */\nfunction wireEvents(pView)\n{\n\tif (!pView.options.Selectable)\n\t{\n\t\treturn;\n\t}\n\n\tlet tmpTargetElementSet = pView.services.ContentAssignment.getElement(pView.options.TargetElementAddress);\n\tif (!tmpTargetElementSet || tmpTargetElementSet.length < 1)\n\t{\n\t\treturn;\n\t}\n\tlet tmpContainer = tmpTargetElementSet[0];\n\tif (!tmpContainer)\n\t{\n\t\treturn;\n\t}\n\n\t// --- Bar click selection (single / multiple modes) ---\n\tif (pView.options.SelectionMode === 'single' || pView.options.SelectionMode === 'multiple')\n\t{\n\t\tlet tmpBars = tmpContainer.querySelectorAll('.pict-histogram-bar[data-histogram-index]');\n\t\tfor (let i = 0; i < tmpBars.length; i++)\n\t\t{\n\t\t\ttmpBars[i].addEventListener('click', (pEvent) =>\n\t\t\t{\n\t\t\t\tlet tmpIndex = parseInt(pEvent.currentTarget.getAttribute('data-histogram-index'), 10);\n\t\t\t\tif (isNaN(tmpIndex))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpView.handleBarClick(tmpIndex);\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Range slider drag ---\n\tif (pView.options.SelectionMode === 'range')\n\t{\n\t\t// Also allow clicking bars to move nearest handle\n\t\tlet tmpBars = tmpContainer.querySelectorAll('.pict-histogram-bar[data-histogram-index]');\n\t\tfor (let i = 0; i < tmpBars.length; i++)\n\t\t{\n\t\t\ttmpBars[i].addEventListener('click', (pEvent) =>\n\t\t\t{\n\t\t\t\tlet tmpIndex = parseInt(pEvent.currentTarget.getAttribute('data-histogram-index'), 10);\n\t\t\t\tif (isNaN(tmpIndex))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpView.handleRangeBarClick(tmpIndex);\n\t\t\t});\n\t\t}\n\n\t\tlet tmpHandles = tmpContainer.querySelectorAll('.pict-histogram-range-handle');\n\t\tfor (let i = 0; i < tmpHandles.length; i++)\n\t\t{\n\t\t\twireRangeHandle(pView, tmpHandles[i], tmpContainer);\n\t\t}\n\t}\n}\n\n/**\n * Wire drag behavior on a single range handle element.\n *\n * @param {object} pView - The histogram view instance\n * @param {Element} pHandle - The handle DOM element\n * @param {Element} pContainer - The histogram container element\n */\nfunction wireRangeHandle(pView, pHandle, pContainer)\n{\n\tlet tmpHandleType = pHandle.getAttribute('data-handle'); // \"start\" or \"end\"\n\tlet tmpVertical = (pView.options.Orientation === 'vertical');\n\n\tlet tmpDragging = false;\n\n\tfunction getSliderBounds()\n\t{\n\t\t// Re-query from pContainer every time because renderHistogram() replaces\n\t\t// the inner HTML, detaching any previously-captured slider element.\n\t\tlet tmpSlider = pContainer.querySelector('.pict-histogram-range-slider-container');\n\t\tif (!tmpSlider)\n\t\t{\n\t\t\treturn { start: 0, size: 1 };\n\t\t}\n\t\tlet tmpRect = tmpSlider.getBoundingClientRect();\n\t\tif (tmpVertical)\n\t\t{\n\t\t\treturn { start: tmpRect.left, size: tmpRect.width || 1 };\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn { start: tmpRect.top, size: tmpRect.height || 1 };\n\t\t}\n\t}\n\n\tfunction onPointerMove(pEvent)\n\t{\n\t\tif (!tmpDragging)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBins = pView.getBins();\n\t\tif (!tmpBins || tmpBins.length === 0)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBounds = getSliderBounds();\n\t\tlet tmpPos = tmpVertical ? pEvent.clientX : pEvent.clientY;\n\t\tlet tmpPct = (tmpPos - tmpBounds.start) / tmpBounds.size;\n\t\ttmpPct = Math.max(0, Math.min(1, tmpPct));\n\n\t\tlet tmpIndex = Math.round(tmpPct * (tmpBins.length - 1));\n\n\t\tif (tmpHandleType === 'start')\n\t\t{\n\t\t\tif (tmpIndex > pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpIndex = pView._selectionRangeEnd;\n\t\t\t}\n\t\t\tpView._selectionRangeStart = tmpIndex;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (tmpIndex < pView._selectionRangeStart)\n\t\t\t{\n\t\t\t\ttmpIndex = pView._selectionRangeStart;\n\t\t\t}\n\t\t\tpView._selectionRangeEnd = tmpIndex;\n\t\t}\n\n\t\tpView._syncSelectionFromRange();\n\t\tpView.renderHistogram();\n\t}\n\n\tfunction onPointerUp()\n\t{\n\t\tif (!tmpDragging)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\ttmpDragging = false;\n\t\tif (typeof (document) !== 'undefined')\n\t\t{\n\t\t\tdocument.removeEventListener('mousemove', onPointerMove);\n\t\t\tdocument.removeEventListener('mouseup', onPointerUp);\n\t\t}\n\t}\n\n\tpHandle.addEventListener('mousedown', (pEvent) =>\n\t{\n\t\tpEvent.preventDefault();\n\t\ttmpDragging = true;\n\t\tif (typeof (document) !== 'undefined')\n\t\t{\n\t\t\tdocument.addEventListener('mousemove', onPointerMove);\n\t\t\tdocument.addEventListener('mouseup', onPointerUp);\n\t\t}\n\t});\n}\n\nmodule.exports = { render, wireEvents };\n","/**\n * CLI renderer for pict-section-histogram.\n *\n * Renders the histogram as ANSI-colored text written directly to stdout\n * (or through the Pict ContentAssignment pipeline if available).\n *\n * This mode is intended for command-line tools that print histogram output\n * without a full terminal UI framework.\n *\n * @module Pict-Histogram-Renderer-CLI\n */\n\n// ANSI color codes (basic 16-color)\nconst ANSI_COLORS = {\n\t'black': '\\x1b[30m',\n\t'red': '\\x1b[31m',\n\t'green': '\\x1b[32m',\n\t'yellow': '\\x1b[33m',\n\t'blue': '\\x1b[34m',\n\t'magenta': '\\x1b[35m',\n\t'cyan': '\\x1b[36m',\n\t'white': '\\x1b[37m',\n\t'reset': '\\x1b[0m',\n\t'bold': '\\x1b[1m',\n\t'dim': '\\x1b[2m'\n};\n\n/**\n * Map a CSS-ish color string to the nearest ANSI color.\n *\n * @param {string} pColor - A color string (name or hex)\n * @returns {string} ANSI escape code\n */\nfunction colorToAnsi(pColor)\n{\n\tif (!pColor)\n\t{\n\t\treturn ANSI_COLORS.blue;\n\t}\n\n\tlet tmpLower = pColor.toLowerCase();\n\n\t// Direct name match\n\tif (ANSI_COLORS[tmpLower])\n\t{\n\t\treturn ANSI_COLORS[tmpLower];\n\t}\n\n\t// Simple hex-to-nearest mapping\n\tif (tmpLower.charAt(0) === '#' && tmpLower.length >= 7)\n\t{\n\t\tlet tmpR = parseInt(tmpLower.substring(1, 3), 16);\n\t\tlet tmpG = parseInt(tmpLower.substring(3, 5), 16);\n\t\tlet tmpB = parseInt(tmpLower.substring(5, 7), 16);\n\n\t\t// Pick nearest basic color\n\t\tif (tmpG > tmpR && tmpG > tmpB)\n\t\t{\n\t\t\treturn ANSI_COLORS.green;\n\t\t}\n\t\tif (tmpR > tmpG && tmpR > tmpB)\n\t\t{\n\t\t\treturn ANSI_COLORS.red;\n\t\t}\n\t\tif (tmpB > tmpR && tmpB > tmpG)\n\t\t{\n\t\t\treturn ANSI_COLORS.blue;\n\t\t}\n\t\tif (tmpR > 200 && tmpG > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.yellow;\n\t\t}\n\t\tif (tmpR > 200 && tmpB > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.magenta;\n\t\t}\n\t\tif (tmpG > 200 && tmpB > 200)\n\t\t{\n\t\t\treturn ANSI_COLORS.cyan;\n\t\t}\n\t}\n\n\treturn ANSI_COLORS.blue;\n}\n\n/**\n * Render a vertical CLI histogram.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The ANSI text output\n */\nfunction renderVertical(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpHeight = tmpOptions.TextHeight || 15;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\tlet tmpBarColor = colorToAnsi(tmpOptions.BarColor);\n\tlet tmpSelectedColor = colorToAnsi(tmpOptions.SelectedBarColor);\n\tlet tmpRangeColor = colorToAnsi(tmpOptions.SelectionRangeColor);\n\tlet tmpReset = ANSI_COLORS.reset;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)\\n';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpValueAxisWidth = String(tmpMaxValue).length + 1;\n\tlet tmpLines = [];\n\n\tfor (let tmpRow = tmpHeight; tmpRow >= 1; tmpRow--)\n\t{\n\t\tlet tmpLine = '';\n\n\t\t// Axis labels\n\t\tif (tmpRow === tmpHeight)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft(String(tmpMaxValue), tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse if (tmpRow === 1)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft('0', tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse if (tmpRow === Math.ceil(tmpHeight / 2))\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft(String(Math.round(tmpMaxValue / 2)), tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + padLeft('', tmpValueAxisWidth) + '|' + tmpReset;\n\t\t}\n\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\t\tlet tmpBarHeight = (tmpVal / tmpMaxValue) * tmpHeight;\n\t\t\tlet tmpFullRows = Math.floor(tmpBarHeight);\n\t\t\tlet tmpFraction = tmpBarHeight - tmpFullRows;\n\n\t\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\t\tlet tmpColor = tmpIsSelected ? tmpSelectedColor : (tmpInRange ? tmpRangeColor : tmpBarColor);\n\n\t\t\tlet tmpChar = ' ';\n\t\t\tif (tmpRow <= tmpFullRows)\n\t\t\t{\n\t\t\t\ttmpChar = tmpBarChar;\n\t\t\t}\n\t\t\telse if (tmpRow === tmpFullRows + 1 && tmpFraction > 0)\n\t\t\t{\n\t\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\t\ttmpChar = tmpPartials[tmpPartialIndex];\n\t\t\t}\n\n\t\t\tif (tmpChar !== ' ')\n\t\t\t{\n\t\t\t\ttmpLine += ' ' + tmpColor + tmpChar + tmpChar + tmpChar + tmpReset;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpLine += ' ';\n\t\t\t}\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Bottom axis\n\tlet tmpAxisLine = ANSI_COLORS.dim + padLeft('', tmpValueAxisWidth) + '+';\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\ttmpAxisLine += '----';\n\t}\n\ttmpAxisLine += tmpReset;\n\ttmpLines.push(tmpAxisLine);\n\n\t// Labels\n\tif (tmpOptions.ShowLabels)\n\t{\n\t\tlet tmpLabelLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\t\ttmpLabelLine += padCenter(tmpLabel.substring(0, 4), 4);\n\t\t}\n\t\ttmpLines.push(tmpLabelLine);\n\t}\n\n\t// Range selection info\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpStart = pView._selectionRangeStart;\n\t\tlet tmpEnd = pView._selectionRangeEnd;\n\t\tlet tmpStartLabel = tmpBins[tmpStart] ? tmpBins[tmpStart][tmpOptions.LabelProperty] : tmpStart;\n\t\tlet tmpEndLabel = tmpBins[tmpEnd] ? tmpBins[tmpEnd][tmpOptions.LabelProperty] : tmpEnd;\n\t\ttmpLines.push('');\n\t\ttmpLines.push(ANSI_COLORS.bold + ' Selection: ' + tmpStartLabel + ' - ' + tmpEndLabel + tmpReset);\n\t}\n\n\treturn tmpLines.join('\\n') + '\\n';\n}\n\n/**\n * Render a horizontal CLI histogram.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The ANSI text output\n */\nfunction renderHorizontal(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpWidth = tmpOptions.TextWidth || 60;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpBarColor = colorToAnsi(tmpOptions.BarColor);\n\tlet tmpSelectedColor = colorToAnsi(tmpOptions.SelectedBarColor);\n\tlet tmpRangeColor = colorToAnsi(tmpOptions.SelectionRangeColor);\n\tlet tmpReset = ANSI_COLORS.reset;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)\\n';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tlet tmpMaxLabelLen = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tif (tmpLabel.length > tmpMaxLabelLen)\n\t\t{\n\t\t\ttmpMaxLabelLen = tmpLabel.length;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpLabelWidth = Math.min(tmpMaxLabelLen, 12);\n\tlet tmpValueWidth = String(tmpMaxValue).length;\n\tlet tmpBarWidth = tmpWidth - tmpLabelWidth - tmpValueWidth - 4;\n\tif (tmpBarWidth < 10)\n\t{\n\t\ttmpBarWidth = 10;\n\t}\n\n\tlet tmpLines = [];\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tlet tmpBarLen = Math.round((tmpVal / tmpMaxValue) * tmpBarWidth);\n\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\tlet tmpColor = tmpIsSelected ? tmpSelectedColor : (tmpInRange ? tmpRangeColor : tmpBarColor);\n\n\t\tlet tmpBar = '';\n\t\tfor (let j = 0; j < tmpBarLen; j++)\n\t\t{\n\t\t\ttmpBar += tmpBarChar;\n\t\t}\n\n\t\tlet tmpLine = ANSI_COLORS.dim + padRight(tmpLabel.substring(0, tmpLabelWidth), tmpLabelWidth) + ' |' + tmpReset;\n\t\ttmpLine += tmpColor + tmpBar + tmpReset;\n\t\ttmpLine += ' ' + tmpVal;\n\n\t\tif (tmpIsSelected)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.bold + ' *' + tmpReset;\n\t\t}\n\t\telse if (tmpInRange)\n\t\t{\n\t\t\ttmpLine += ANSI_COLORS.dim + ' ~' + tmpReset;\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Range info\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpStart = pView._selectionRangeStart;\n\t\tlet tmpEnd = pView._selectionRangeEnd;\n\t\tlet tmpStartLabel = tmpBins[tmpStart] ? tmpBins[tmpStart][tmpOptions.LabelProperty] : tmpStart;\n\t\tlet tmpEndLabel = tmpBins[tmpEnd] ? tmpBins[tmpEnd][tmpOptions.LabelProperty] : tmpEnd;\n\t\ttmpLines.push('');\n\t\ttmpLines.push(ANSI_COLORS.bold + ' Selection: ' + tmpStartLabel + ' - ' + tmpEndLabel + tmpReset);\n\t}\n\n\treturn tmpLines.join('\\n') + '\\n';\n}\n\n/**\n * Render in CLI mode. Writes to ContentAssignment if available, otherwise\n * falls back to process.stdout.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpText;\n\tif (pView.options.Orientation === 'vertical')\n\t{\n\t\ttmpText = renderVertical(pView);\n\t}\n\telse\n\t{\n\t\ttmpText = renderHorizontal(pView);\n\t}\n\n\t// Try ContentAssignment first (might be mocked in tests or bridged)\n\tif (pView.services && pView.services.ContentAssignment)\n\t{\n\t\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpText);\n\t}\n\telse if (typeof (process) !== 'undefined' && process.stdout)\n\t{\n\t\tprocess.stdout.write(tmpText);\n\t}\n}\n\n// No interactive events in CLI mode\nfunction wireEvents()\n{\n\t// No-op for CLI\n}\n\n// --- Utility ---\n\nfunction padLeft(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = ' ' + tmpStr;\n\t}\n\treturn tmpStr;\n}\n\nfunction padRight(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = tmpStr + ' ';\n\t}\n\treturn tmpStr;\n}\n\nfunction padCenter(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = (tmpStr.length % 2 === 0) ? (tmpStr + ' ') : (' ' + tmpStr);\n\t}\n\treturn tmpStr;\n}\n\nmodule.exports = { render, wireEvents, renderVertical, renderHorizontal, colorToAnsi, ANSI_COLORS };\n","/**\n * Console UI (blessed) renderer for pict-section-histogram.\n *\n * Renders the histogram as text art through the Pict ContentAssignment\n * pipeline, suitable for blessed/ncurses terminal UI widgets.\n *\n * The output is assigned via ContentAssignment so the pict-terminalui\n * bridge (customAssignFunction) can project it into blessed boxes.\n *\n * @module Pict-Histogram-Renderer-ConsoleUI\n */\n\n/**\n * Build a vertical text histogram.\n *\n * Each column is one bar. Rows go from top (max value) to bottom (0).\n * Uses block characters for fractional rows.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The rendered text block\n */\nfunction renderVertical(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpHeight = tmpOptions.TextHeight || 15;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\tlet tmpEmptyChar = tmpOptions.EmptyCharacter;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\t// Determine label width for the value axis\n\tlet tmpValueAxisWidth = String(tmpMaxValue).length + 1;\n\n\t// Build the grid top-down\n\tlet tmpLines = [];\n\n\tfor (let tmpRow = tmpHeight; tmpRow >= 1; tmpRow--)\n\t{\n\t\tlet tmpLine = '';\n\n\t\t// Value axis label (only on a few rows)\n\t\tif (tmpRow === tmpHeight)\n\t\t{\n\t\t\ttmpLine += padLeft(String(tmpMaxValue), tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse if (tmpRow === 1)\n\t\t{\n\t\t\ttmpLine += padLeft('0', tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse if (tmpRow === Math.ceil(tmpHeight / 2))\n\t\t{\n\t\t\ttmpLine += padLeft(String(Math.round(tmpMaxValue / 2)), tmpValueAxisWidth) + '|';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpLine += padLeft('', tmpValueAxisWidth) + '|';\n\t\t}\n\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\t\tlet tmpBarHeight = (tmpVal / tmpMaxValue) * tmpHeight;\n\t\t\tlet tmpFullRows = Math.floor(tmpBarHeight);\n\t\t\tlet tmpFraction = tmpBarHeight - tmpFullRows;\n\n\t\t\tlet tmpChar = tmpEmptyChar;\n\t\t\tif (tmpRow <= tmpFullRows)\n\t\t\t{\n\t\t\t\ttmpChar = tmpBarChar;\n\t\t\t}\n\t\t\telse if (tmpRow === tmpFullRows + 1 && tmpFraction > 0)\n\t\t\t{\n\t\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\t\ttmpChar = tmpPartials[tmpPartialIndex];\n\t\t\t}\n\n\t\t\t// Mark selected bins\n\t\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\n\t\t\tif (tmpIsSelected && tmpChar !== tmpEmptyChar)\n\t\t\t{\n\t\t\t\ttmpChar = '*';\n\t\t\t}\n\t\t\telse if (tmpInRange && tmpChar !== tmpEmptyChar)\n\t\t\t{\n\t\t\t\ttmpChar = '#';\n\t\t\t}\n\n\t\t\t// Each bar is 3 chars wide with 1 char gap\n\t\t\ttmpLine += ' ' + tmpChar + tmpChar + tmpChar;\n\t\t}\n\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Bottom axis\n\tlet tmpAxisLine = padLeft('', tmpValueAxisWidth) + '+';\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\ttmpAxisLine += '----';\n\t}\n\ttmpLines.push(tmpAxisLine);\n\n\t// Labels row\n\tif (tmpOptions.ShowLabels)\n\t{\n\t\tlet tmpLabelLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\t\ttmpLabelLine += padCenter(tmpLabel.substring(0, 4), 4);\n\t\t}\n\t\ttmpLines.push(tmpLabelLine);\n\t}\n\n\t// Selection range indicator\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\tlet tmpRangeLine = padLeft('', tmpValueAxisWidth) + ' ';\n\t\tfor (let i = 0; i < tmpBins.length; i++)\n\t\t{\n\t\t\tif (i === pView._selectionRangeStart)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' [ ';\n\t\t\t}\n\t\t\telse if (i === pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' ] ';\n\t\t\t}\n\t\t\telse if (i > pView._selectionRangeStart && i < pView._selectionRangeEnd)\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' - ';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpRangeLine += ' ';\n\t\t\t}\n\t\t}\n\t\ttmpLines.push(tmpRangeLine);\n\t}\n\n\treturn tmpLines.join('\\n');\n}\n\n/**\n * Build a horizontal text histogram.\n *\n * Each row is one bar growing rightward.\n *\n * @param {object} pView - The histogram view instance\n * @returns {string} The rendered text block\n */\nfunction renderHorizontal(pView)\n{\n\tlet tmpBins = pView.getBins();\n\tlet tmpOptions = pView.options;\n\tlet tmpWidth = tmpOptions.TextWidth || 60;\n\tlet tmpBarChar = tmpOptions.BarCharacter;\n\tlet tmpPartials = tmpOptions.BarPartialCharacters;\n\n\tif (!tmpBins || tmpBins.length === 0)\n\t{\n\t\treturn '(no data)';\n\t}\n\n\tlet tmpMaxValue = 0;\n\tlet tmpMaxLabelLen = 0;\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tif (tmpVal > tmpMaxValue)\n\t\t{\n\t\t\ttmpMaxValue = tmpVal;\n\t\t}\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tif (tmpLabel.length > tmpMaxLabelLen)\n\t\t{\n\t\t\ttmpMaxLabelLen = tmpLabel.length;\n\t\t}\n\t}\n\tif (tmpMaxValue === 0)\n\t{\n\t\ttmpMaxValue = 1;\n\t}\n\n\tlet tmpLabelWidth = Math.min(tmpMaxLabelLen, 12);\n\tlet tmpBarWidth = tmpWidth - tmpLabelWidth - 2; // space for \" |\"\n\tif (tmpBarWidth < 10)\n\t{\n\t\ttmpBarWidth = 10;\n\t}\n\n\tlet tmpLines = [];\n\n\tfor (let i = 0; i < tmpBins.length; i++)\n\t{\n\t\tlet tmpVal = tmpBins[i][tmpOptions.ValueProperty] || 0;\n\t\tlet tmpLabel = String(tmpBins[i][tmpOptions.LabelProperty] || '');\n\t\tlet tmpBarLen = (tmpVal / tmpMaxValue) * tmpBarWidth;\n\t\tlet tmpFullChars = Math.floor(tmpBarLen);\n\t\tlet tmpFraction = tmpBarLen - tmpFullChars;\n\n\t\tlet tmpBar = '';\n\t\tfor (let j = 0; j < tmpFullChars; j++)\n\t\t{\n\t\t\ttmpBar += tmpBarChar;\n\t\t}\n\t\tif (tmpFraction > 0 && tmpFullChars < tmpBarWidth)\n\t\t{\n\t\t\tlet tmpPartialIndex = Math.round(tmpFraction * (tmpPartials.length - 1));\n\t\t\ttmpBar += tmpPartials[tmpPartialIndex];\n\t\t}\n\n\t\t// Mark selected\n\t\tlet tmpIsSelected = pView.isIndexSelected(i);\n\t\tlet tmpInRange = !tmpIsSelected && pView.isIndexInRange(i);\n\t\tlet tmpMarker = tmpIsSelected ? '*' : (tmpInRange ? '~' : '');\n\n\t\tlet tmpValueStr = tmpOptions.ShowValues ? (' ' + tmpVal) : '';\n\t\tlet tmpLine = padRight(tmpLabel.substring(0, tmpLabelWidth), tmpLabelWidth) + ' |' + tmpBar + tmpValueStr + tmpMarker;\n\t\ttmpLines.push(tmpLine);\n\t}\n\n\t// Range indicator for range selection\n\tif (tmpOptions.Selectable && tmpOptions.SelectionMode === 'range')\n\t{\n\t\ttmpLines.push('');\n\t\ttmpLines.push(padRight('', tmpLabelWidth) + ' Range: [' + pView._selectionRangeStart + ' - ' + pView._selectionRangeEnd + ']');\n\t}\n\n\treturn tmpLines.join('\\n');\n}\n\n/**\n * Render via ContentAssignment for consoleui mode.\n *\n * @param {object} pView - The histogram view instance\n */\nfunction render(pView)\n{\n\tlet tmpText;\n\tif (pView.options.Orientation === 'vertical')\n\t{\n\t\ttmpText = renderVertical(pView);\n\t}\n\telse\n\t{\n\t\ttmpText = renderHorizontal(pView);\n\t}\n\n\tpView.services.ContentAssignment.assignContent(pView.options.TargetElementAddress, tmpText);\n}\n\n// No interactive events for consoleui — input is handled by the blessed widget layer\nfunction wireEvents()\n{\n\t// No-op for consoleui\n}\n\n// --- Utility ---\n\nfunction padLeft(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = ' ' + tmpStr;\n\t}\n\treturn tmpStr;\n}\n\nfunction padRight(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = tmpStr + ' ';\n\t}\n\treturn tmpStr;\n}\n\nfunction padCenter(pStr, pLen)\n{\n\tlet tmpStr = String(pStr);\n\twhile (tmpStr.length < pLen)\n\t{\n\t\ttmpStr = (tmpStr.length % 2 === 0) ? (tmpStr + ' ') : (' ' + tmpStr);\n\t}\n\treturn tmpStr;\n}\n\nmodule.exports = { render, wireEvents, renderVertical, renderHorizontal };\n","module.exports={\n \"name\": \"pict-view\",\n \"version\": \"1.0.67\",\n \"description\": \"Pict View Base Class\",\n \"main\": \"source/Pict-View.js\",\n \"scripts\": {\n \"test\": \"npx quack test\",\n \"tests\": \"npx quack test -g\",\n \"start\": \"node source/Pict-View.js\",\n \"coverage\": \"npx quack coverage\",\n \"build\": \"npx quack build\",\n \"docker-dev-build\": \"docker build ./ -f Dockerfile_LUXURYCode -t pict-view-image:local\",\n \"docker-dev-run\": \"docker run -it -d --name pict-view-dev -p 30001:8080 -p 38086:8086 -v \\\"$PWD/.config:/home/coder/.config\\\" -v \\\"$PWD:/home/coder/pict-view\\\" -u \\\"$(id -u):$(id -g)\\\" -e \\\"DOCKER_USER=$USER\\\" pict-view-image:local\",\n \"docker-dev-shell\": \"docker exec -it pict-view-dev /bin/bash\",\n \"types\": \"tsc -p .\",\n \"lint\": \"eslint source/**\"\n },\n \"types\": \"types/source/Pict-View.d.ts\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/stevenvelozo/pict-view.git\"\n },\n \"author\": \"steven velozo <steven@velozo.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/stevenvelozo/pict-view/issues\"\n },\n \"homepage\": \"https://github.com/stevenvelozo/pict-view#readme\",\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.1\",\n \"browser-env\": \"^3.3.0\",\n \"eslint\": \"^9.39.1\",\n \"pict\": \"^1.0.348\",\n \"quackage\": \"^1.0.58\",\n \"typescript\": \"^5.9.3\"\n },\n \"mocha\": {\n \"diff\": true,\n \"extension\": [\n \"js\"\n ],\n \"package\": \"./package.json\",\n \"reporter\": \"spec\",\n \"slow\": \"75\",\n \"timeout\": \"5000\",\n \"ui\": \"tdd\",\n \"watch-files\": [\n \"source/**/*.js\",\n \"test/**/*.js\"\n ],\n \"watch-ignore\": [\n \"lib/vendor\"\n ]\n },\n \"dependencies\": {\n \"fable\": \"^3.1.63\",\n \"fable-serviceproviderbase\": \"^3.0.19\"\n }\n}\n","\nconst libFableServiceBase = require('fable-serviceproviderbase');\n\nconst libPackage = require('../package.json');\n\nconst defaultPictViewSettings = (\n\t{\n\t\tDefaultRenderable: false,\n\t\tDefaultDestinationAddress: false,\n\t\tDefaultTemplateRecordAddress: false,\n\n\t\tViewIdentifier: false,\n\n\t\t// If this is set to true, when the App initializes this will.\n\t\t// After the App initializes, initialize will be called as soon as it's added.\n\t\tAutoInitialize: true,\n\t\tAutoInitializeOrdinal: 0,\n\n\t\t// If this is set to true, when the App autorenders (on load) this will.\n\t\t// After the App initializes, render will be called as soon as it's added.\n\t\tAutoRender: true,\n\t\tAutoRenderOrdinal: 0,\n\n\t\tAutoSolveWithApp: true,\n\t\tAutoSolveOrdinal: 0,\n\n\t\tCSSHash: false,\n\t\tCSS: false,\n\t\tCSSProvider: false,\n\t\tCSSPriority: 500,\n\n\t\tTemplates: [],\n\n\t\tDefaultTemplates: [],\n\n\t\tRenderables: [],\n\n\t\tManifests: {}\n\t});\n\n/** @typedef {(error?: Error) => void} ErrorCallback */\n/** @typedef {number | boolean} PictTimestamp */\n\n/**\n * @typedef {'replace' | 'append' | 'prepend' | 'append_once' | 'virtual-assignment'} RenderMethod\n */\n/**\n * @typedef {Object} Renderable\n *\n * @property {string} RenderableHash - A unique hash for the renderable.\n * @property {string} TemplateHash - The hash of the template to use for rendering this renderable.\n * @property {string} [DefaultTemplateRecordAddress] - The default address for resolving the data record for this renderable.\n * @property {string} [ContentDestinationAddress] - The default address (DOM CSS selector) for rendering the content of this renderable.\n * @property {RenderMethod} [RenderMethod=replace] - The method to use when projecting the renderable to the DOM ('replace', 'append', 'prepend', 'append_once', 'virtual-assignment').\n * @property {string} [TestAddress] - The address to use for testing the renderable.\n * @property {string} [TransactionHash] - The transaction hash for the root renderable.\n * @property {string} [RootRenderableViewHash] - The hash of the root renderable.\n * @property {string} [Content] - The rendered content for this renderable, if applicable.\n */\n\n/**\n * Represents a view in the Pict ecosystem.\n */\nclass PictView extends libFableServiceBase\n{\n\t/**\n\t * @param {any} pFable - The Fable object that this service is attached to.\n\t * @param {any} [pOptions] - (optional) The options for this service.\n\t * @param {string} [pServiceHash] - (optional) The hash of the service.\n\t */\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\t// Intersect default options, parent constructor, service information\n\t\tlet tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultPictViewSettings)), pOptions);\n\t\tsuper(pFable, tmpOptions, pServiceHash);\n\t\t//FIXME: add types to fable and ancillaries\n\t\t/** @type {any} */\n\t\tthis.fable;\n\t\t/** @type {any} */\n\t\tthis.options;\n\t\t/** @type {String} */\n\t\tthis.UUID;\n\t\t/** @type {String} */\n\t\tthis.Hash;\n\t\t/** @type {any} */\n\t\tthis.log;\n\n\t\tconst tmpHashIsUUID = this.Hash === this.UUID;\n\t\t//NOTE: since many places are using the view UUID as the HTML element ID, we prefix it to avoid starting with a number\n\t\tthis.UUID = `V-${this.UUID}`;\n\t\tif (tmpHashIsUUID)\n\t\t{\n\t\t\tthis.Hash = this.UUID;\n\t\t}\n\n\t\tif (!this.options.ViewIdentifier)\n\t\t{\n\t\t\tthis.options.ViewIdentifier = `AutoViewID-${this.fable.getUUID()}`;\n\t\t}\n\t\tthis.serviceType = 'PictView';\n\t\t/** @type {Record<string, any>} */\n\t\tthis._Package = libPackage;\n\t\t// Convenience and consistency naming\n\t\t/** @type {import('pict') & { log: any, instantiateServiceProviderWithoutRegistration: (hash: String) => any, instantiateServiceProviderIfNotExists: (hash: string) => any, TransactionTracking: import('pict/types/source/services/Fable-Service-TransactionTracking') }} */\n\t\tthis.pict = this.fable;\n\t\t// Wire in the essential Pict application state\n\t\tthis.AppData = this.pict.AppData;\n\t\tthis.Bundle = this.pict.Bundle;\n\n\t\t/** @type {PictTimestamp} */\n\t\tthis.initializeTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastSolvedTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastRenderedTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastMarshalFromViewTimestamp = false;\n\t\t/** @type {PictTimestamp} */\n\t\tthis.lastMarshalToViewTimestamp = false;\n\n\t\tthis.pict.instantiateServiceProviderIfNotExists('TransactionTracking');\n\n\t\t// Load all templates from the array in the options\n\t\t// Templates are in the form of {Hash:'Some-Template-Hash',Template:'Template content',Source:'TemplateSource'}\n\t\tfor (let i = 0; i < this.options.Templates.length; i++)\n\t\t{\n\t\t\tlet tmpTemplate = this.options.Templates[i];\n\n\t\t\tif (!('Hash' in tmpTemplate) || !('Template' in tmpTemplate))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Template ${i} in the options array.`, tmpTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpTemplate.Source = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addTemplate(tmpTemplate.Hash, tmpTemplate.Template, tmpTemplate.Source);\n\t\t\t}\n\t\t}\n\n\t\t// Load all default templates from the array in the options\n\t\t// Templates are in the form of {Prefix:'',Postfix:'-List-Row',Template:'Template content',Source:'TemplateSourceString'}\n\t\tfor (let i = 0; i < this.options.DefaultTemplates.length; i++)\n\t\t{\n\t\t\tlet tmpDefaultTemplate = this.options.DefaultTemplates[i];\n\n\t\t\tif (!('Postfix' in tmpDefaultTemplate) || !('Template' in tmpDefaultTemplate))\n\t\t\t{\n\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Default Template ${i} in the options array.`, tmpDefaultTemplate);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!tmpDefaultTemplate.Source)\n\t\t\t\t{\n\t\t\t\t\ttmpDefaultTemplate.Source = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} options object.`;\n\t\t\t\t}\n\t\t\t\tthis.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix, tmpDefaultTemplate.Postfix, tmpDefaultTemplate.Template, tmpDefaultTemplate.Source);\n\t\t\t}\n\t\t}\n\n\t\t// Load the CSS if it's available\n\t\tif (this.options.CSS)\n\t\t{\n\t\t\tlet tmpCSSHash = this.options.CSSHash ? this.options.CSSHash : `View-${this.options.ViewIdentifier}`;\n\t\t\tlet tmpCSSProvider = this.options.CSSProvider ? this.options.CSSProvider : tmpCSSHash;\n\t\t\tthis.pict.CSSMap.addCSS(tmpCSSHash, this.options.CSS, tmpCSSProvider, this.options.CSSPriority);\n\t\t}\n\n\t\t// Load all renderables\n\t\t// Renderables are launchable renderable instructions with templates\n\t\t// They look as such: {Identifier:'ContentEntry', TemplateHash:'Content-Entry-Section-Main', ContentDestinationAddress:'#ContentSection', RecordAddress:'AppData.Content.DefaultText', ManifestTransformation:'ManyfestHash', ManifestDestinationAddress:'AppData.Content.DataToTransformContent'}\n\t\t// The only parts that are necessary are Identifier and Template\n\t\t// A developer can then do render('ContentEntry') and it just kinda works. Or they can override the ContentDestinationAddress\n\t\t/** @type {Record<String, Renderable>} */\n\t\tthis.renderables = {};\n\t\tfor (let i = 0; i < this.options.Renderables.length; i++)\n\t\t{\n\t\t\t/** @type {Renderable} */\n\t\t\tlet tmpRenderable = this.options.Renderables[i];\n\t\t\tthis.addRenderable(tmpRenderable);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a renderable to the view.\n\t *\n\t * @param {string | Renderable} pRenderableHash - The hash of the renderable, or a renderable object.\n\t * @param {string} [pTemplateHash] - (optional) The hash of the template for the renderable.\n\t * @param {string} [pDefaultTemplateRecordAddress] - (optional) The default data address for the template.\n\t * @param {string} [pDefaultDestinationAddress] - (optional) The default destination address for the renderable.\n\t * @param {RenderMethod} [pRenderMethod=replace] - (optional) The method to use when rendering the renderable (ex. 'replace').\n\t */\n\taddRenderable(pRenderableHash, pTemplateHash, pDefaultTemplateRecordAddress, pDefaultDestinationAddress, pRenderMethod)\n\t{\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\n\t\tif (typeof(pRenderableHash) == 'object')\n\t\t{\n\t\t\t// The developer passed in the renderable as an object.\n\t\t\t// Use theirs instead!\n\t\t\ttmpRenderable = pRenderableHash;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/** @type {RenderMethod} */\n\t\t\tlet tmpRenderMethod = (typeof(pRenderMethod) !== 'string') ? pRenderMethod : 'replace';\n\t\t\ttmpRenderable = (\n\t\t\t\t{\n\t\t\t\t\tRenderableHash: pRenderableHash,\n\t\t\t\t\tTemplateHash: pTemplateHash,\n\t\t\t\t\tDefaultTemplateRecordAddress: pDefaultTemplateRecordAddress,\n\t\t\t\t\tContentDestinationAddress: pDefaultDestinationAddress,\n\t\t\t\t\tRenderMethod: tmpRenderMethod\n\t\t\t\t});\n\t\t}\n\n\t\tif ((typeof(tmpRenderable.RenderableHash) != 'string') || (typeof(tmpRenderable.TemplateHash) != 'string'))\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not load Renderable; RenderableHash or TemplateHash are invalid.`, tmpRenderable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} adding renderable [${tmpRenderable.RenderableHash}] pointed to template ${tmpRenderable.TemplateHash}.`);\n\t\t\t}\n\n\t\t\tthis.renderables[tmpRenderable.RenderableHash] = tmpRenderable;\n\t\t}\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Initialization */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is initialized.\n\t */\n\tonBeforeInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeInitializeAsync(fCallback)\n\t{\n\t\tthis.onBeforeInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is initialized.\n\t */\n\tonInitialize()\n\t{\n\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonInitializeAsync(fCallback)\n\t{\n\t\tthis.onInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Performs view initialization.\n\t */\n\tinitialize()\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialize:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tthis.onBeforeInitialize();\n\t\t\tthis.onInitialize();\n\t\t\tthis.onAfterInitialize();\n\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialize called but initialization is already completed. Aborting.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Performs view initialization (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tinitializeAsync(fCallback)\n\t{\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initializeAsync:`);\n\t\t}\n\n\t\tif (!this.initializeTimestamp)\n\t\t{\n\t\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t{\n\t\t\t\tthis.log.info(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} beginning initialization...`);\n\t\t\t}\n\n\t\t\ttmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onInitializeAsync.bind(this));\n\t\t\ttmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));\n\n\t\t\ttmpAnticipate.wait(\n\t\t\t\t/** @param {Error} pError */\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialization failed: ${pError.message || pError}`, { stack: pError.stack });\n\t\t\t\t\t}\n\t\t\t\t\tthis.initializeTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\t\tif (this.pict.LogNoisiness > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.info(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} initialization complete.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fCallback();\n\t\t\t\t});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} async initialize called but initialization is already completed. Aborting.`);\n\t\t\t// TODO: Should this be an error?\n\t\t\treturn fCallback();\n\t\t}\n\t}\n\n\tonAfterInitialize()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterInitialize:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is initialized (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\tthis.onAfterInitialize();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Render */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is rendered.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that will be rendered.\n\t */\n\tonBeforeRender(pRenderable)\n\t{\n\t\t// Overload this to mess with stuff before the content gets generated from the template\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeRender:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is rendered (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that will be rendered.\n\t */\n\tonBeforeRenderAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onBeforeRender(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is projected into the DOM.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that will be projected.\n\t */\n\tonBeforeProject(pRenderable)\n\t{\n\t\t// Overload this to mess with stuff before the content gets generated from the template\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeProject:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is projected into the DOM (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that will be projected.\n\t */\n\tonBeforeProjectAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onBeforeProject(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Builds the render options for a renderable.\n\t *\n\t * For DRY purposes on the three flavors of render.\n\t *\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbuildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\tlet tmpRenderOptions = {Valid: true};\n\t\ttmpRenderOptions.RenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t\t\t\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ?\n\t\t\t\t\t\t\t\tthis.options.DefaultRenderable : false;\n\t\tif (!tmpRenderOptions.RenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not find a suitable RenderableHash ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\ttmpRenderOptions.Renderable = this.renderables[tmpRenderOptions.RenderableHash];\n\t\tif (!tmpRenderOptions.Renderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\ttmpRenderOptions.DestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t(typeof (tmpRenderOptions.Renderable.ContentDestinationAddress) === 'string') ? tmpRenderOptions.Renderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : false;\n\t\tif (!tmpRenderOptions.DestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderOptions.RenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address (param ${pRenderDestinationAddress}).`);\n\t\t\ttmpRenderOptions.Valid = false;\n\t\t}\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRenderOptions.RecordAddress = 'Passed in as object';\n\t\t\ttmpRenderOptions.Record = pTemplateRecordAddress;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderOptions.RecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderOptions.Renderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderOptions.Renderable.DefaultTemplateRecordAddress :\n\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\t\t\ttmpRenderOptions.Record = (typeof (tmpRenderOptions.RecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRenderOptions.RecordAddress) : undefined;\n\t\t}\n\n\t\treturn tmpRenderOptions;\n\t}\n\n\t/**\n\t * Assigns the content to the destination address.\n\t *\n\t * For DRY purposes on the three flavors of render.\n\t *\n\t * @param {Renderable} pRenderable - The renderable to render.\n\t * @param {string} pRenderDestinationAddress - The address where the renderable will be rendered.\n\t * @param {string} pContent - The content to render.\n\t * @returns {boolean} - Returns true if the content was assigned successfully.\n\t * @memberof PictView\n\t */\n\tassignRenderContent(pRenderable, pRenderDestinationAddress, pContent)\n\t{\n\t\treturn this.pict.ContentAssignment.projectContent(pRenderable.RenderMethod, pRenderDestinationAddress, pContent, pRenderable.TestAddress);\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @return {boolean}\n\t */\n\trender(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable)\n\t{\n\t\treturn this.renderWithScope(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable);\n\t}\n\n\t/**\n\t * Render a renderable from this view, providing a specifici scope for the template.\n\t *\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @return {boolean}\n\t */\n\trenderWithScope(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable)\n\t{\n\t\tlet tmpRenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ? this.options.DefaultRenderable : false;\n\t\tif (!tmpRenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it is not a valid renderable.`);\n\t\t\treturn false;\n\t\t}\n\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\t\tif (tmpRenderableHash == '__Virtual')\n\t\t{\n\t\t\ttmpRenderable = {\n\t\t\t\tRenderableHash: '__Virtual',\n\t\t\t\tTemplateHash: this.renderables[this.options.DefaultRenderable].TemplateHash,\n\t\t\t\tContentDestinationAddress: (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null,\n\t\t\t\tRenderMethod: 'virtual-assignment',\n\t\t\t\tTransactionHash: pRootRenderable && pRootRenderable.TransactionHash,\n\t\t\t\tRootRenderableViewHash: pRootRenderable && pRootRenderable.RootRenderableViewHash,\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderable = Object.assign({}, this.renderables[tmpRenderableHash]);\n\t\t\ttmpRenderable.ContentDestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null;\n\t\t}\n\n\t\tif (!tmpRenderable.TransactionHash)\n\t\t{\n\t\t\ttmpRenderable.TransactionHash = `ViewRender-V-${this.options.ViewIdentifier}-R-${tmpRenderableHash}-U-${this.pict.getUUID()}`;\n\t\t\ttmpRenderable.RootRenderableViewHash = this.Hash;\n\t\t\tthis.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);\n\t\t}\n\n\t\tif (!tmpRenderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!tmpRenderable.ContentDestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tlet tmpRecordAddress;\n\t\tlet tmpRecord;\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRecord = pTemplateRecordAddress;\n\t\t\ttmpRecordAddress = 'Passed in as object';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderable.DefaultTemplateRecordAddress :\n\t\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\n\t\t\ttmpRecord = (typeof (tmpRecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRecordAddress) : undefined;\n\t\t}\n\n\t\t// Execute the developer-overridable pre-render behavior\n\t\tthis.onBeforeRender(tmpRenderable);\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] Renderable[${tmpRenderableHash}] Destination[${tmpRenderable.ContentDestinationAddress}] TemplateRecordAddress[${tmpRecordAddress}] render:`);\n\t\t}\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Beginning Render of Renderable[${tmpRenderableHash}] to Destination [${tmpRenderable.ContentDestinationAddress}]...`);\n\t\t}\n\t\t// Generate the content output from the template and data\n\t\ttmpRenderable.Content = this.pict.parseTemplateByHash(tmpRenderable.TemplateHash, tmpRecord, null, [this], pScope, { RootRenderable: typeof pRootRenderable === 'object' ? pRootRenderable : tmpRenderable });\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Assigning Renderable[${tmpRenderableHash}] content length ${tmpRenderable.Content.length} to Destination [${tmpRenderable.ContentDestinationAddress}] using render method [${tmpRenderable.RenderMethod}].`);\n\t\t}\n\n\t\tthis.onBeforeProject(tmpRenderable);\n\t\tthis.onProject(tmpRenderable);\n\n\t\tif (tmpRenderable.RenderMethod !== 'virtual-assignment')\n\t\t{\n\t\t\tthis.onAfterProject(tmpRenderable);\n\n\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\tthis.onAfterRender(tmpRenderable);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t *\n\t * @return {void}\n\t */\n\trenderAsync(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback)\n\t{\n\t\treturn this.renderWithScopeAsync(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback);\n\t}\n\n\t/**\n\t * Render a renderable from this view.\n\t *\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.\n\t * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t *\n\t * @return {void}\n\t */\n\trenderWithScopeAsync(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, pRootRenderable, fCallback)\n\t{\n\t\tlet tmpRenderableHash = (typeof (pRenderableHash) === 'string') ? pRenderableHash :\n\t\t\t(typeof (this.options.DefaultRenderable) == 'string') ? this.options.DefaultRenderable : false;\n\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateRecordAddress) === 'function') ? pTemplateRecordAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\t(typeof(pRootRenderable) === 'function') ? pRootRenderable :\n\t\t\t\t\t\t\tnull;\n\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} renderAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tif (!tmpRenderableHash)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not asynchronously render ${tmpRenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`);\n\t\t\treturn tmpCallback(new Error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not asynchronously render ${tmpRenderableHash} (param ${pRenderableHash}because it is not a valid renderable.`));\n\t\t}\n\n\t\t/** @type {Renderable} */\n\t\tlet tmpRenderable;\n\t\tif (tmpRenderableHash == '__Virtual')\n\t\t{\n\t\t\ttmpRenderable = {\n\t\t\t\tRenderableHash: '__Virtual',\n\t\t\t\tTemplateHash: this.renderables[this.options.DefaultRenderable].TemplateHash,\n\t\t\t\tContentDestinationAddress: (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress : (typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null,\n\t\t\t\tRenderMethod: 'virtual-assignment',\n\t\t\t\tTransactionHash: pRootRenderable && typeof pRootRenderable !== 'function' && pRootRenderable.TransactionHash,\n\t\t\t\tRootRenderableViewHash: pRootRenderable && typeof pRootRenderable !== 'function' && pRootRenderable.RootRenderableViewHash,\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRenderable = Object.assign({}, this.renderables[tmpRenderableHash]);\n\t\t\ttmpRenderable.ContentDestinationAddress = (typeof (pRenderDestinationAddress) === 'string') ? pRenderDestinationAddress :\n\t\t\t\t(typeof (tmpRenderable.ContentDestinationAddress) === 'string') ? tmpRenderable.ContentDestinationAddress :\n\t\t\t\t(typeof (this.options.DefaultDestinationAddress) === 'string') ? this.options.DefaultDestinationAddress : null;\n\t\t}\n\n\t\tif (!tmpRenderable.TransactionHash)\n\t\t{\n\t\t\ttmpRenderable.TransactionHash = `ViewRender-V-${this.options.ViewIdentifier}-R-${tmpRenderableHash}-U-${this.pict.getUUID()}`;\n\t\t\ttmpRenderable.RootRenderableViewHash = this.Hash;\n\t\t\tthis.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);\n\t\t}\n\n\t\tif (!tmpRenderable)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`);\n\t\t\treturn tmpCallback(new Error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not exist.`));\n\t\t}\n\n\t\tif (!tmpRenderable.ContentDestinationAddress)\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render ${tmpRenderableHash} (param ${pRenderableHash}) because it does not have a valid destination address.`);\n\t\t\treturn tmpCallback(new Error(`Could not render ${tmpRenderableHash}`));\n\t\t}\n\n\t\tlet tmpRecordAddress;\n\t\tlet tmpRecord;\n\n\t\tif (typeof(pTemplateRecordAddress) === 'object')\n\t\t{\n\t\t\ttmpRecord = pTemplateRecordAddress;\n\t\t\ttmpRecordAddress = 'Passed in as object';\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpRecordAddress = (typeof (pTemplateRecordAddress) === 'string') ? pTemplateRecordAddress :\n\t\t\t\t(typeof (tmpRenderable.DefaultTemplateRecordAddress) === 'string') ? tmpRenderable.DefaultTemplateRecordAddress :\n\t\t\t\t\t(typeof (this.options.DefaultTemplateRecordAddress) === 'string') ? this.options.DefaultTemplateRecordAddress : false;\n\n\t\t\ttmpRecord = (typeof (tmpRecordAddress) === 'string') ? this.pict.DataProvider.getDataByAddress(tmpRecordAddress) : undefined;\n\t\t}\n\n\t\tif (this.pict.LogControlFlow)\n\t\t{\n\t\t\tthis.log.trace(`PICT-ControlFlow VIEW [${this.UUID}]::[${this.Hash}] Renderable[${tmpRenderableHash}] Destination[${tmpRenderable.ContentDestinationAddress}] TemplateRecordAddress[${tmpRecordAddress}] renderAsync:`);\n\t\t}\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Beginning Asynchronous Render (callback-style)...`);\n\t\t}\n\n\t\tlet tmpAnticipate = this.fable.newAnticipate();\n\n\t\ttmpAnticipate.anticipate(\n\t\t\t(fOnBeforeRenderCallback) =>\n\t\t\t{\n\t\t\t\tthis.onBeforeRenderAsync(fOnBeforeRenderCallback, tmpRenderable);\n\t\t\t});\n\n\t\ttmpAnticipate.anticipate(\n\t\t\t(fAsyncTemplateCallback) =>\n\t\t\t{\n\t\t\t\t// Render the template (asynchronously)\n\t\t\t\tthis.pict.parseTemplateByHash(tmpRenderable.TemplateHash, tmpRecord,\n\t\t\t\t\t(pError, pContent) =>\n\t\t\t\t\t{\n\t\t\t\t\t\tif (pError)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render (asynchronously) ${tmpRenderableHash} (param ${pRenderableHash}) because it did not parse the template.`, pError);\n\t\t\t\t\t\t\treturn fAsyncTemplateCallback(pError);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttmpRenderable.Content = pContent;\n\n\t\t\t\t\t\treturn fAsyncTemplateCallback();\n\t\t\t\t\t}, [this], pScope, { RootRenderable: typeof pRootRenderable === 'object' ? pRootRenderable : tmpRenderable });\n\t\t\t});\n\n\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t{\n\t\t\tthis.onBeforeProjectAsync(fNext, tmpRenderable);\n\t\t});\n\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t{\n\t\t\tthis.onProjectAsync(fNext, tmpRenderable);\n\t\t});\n\n\t\tif (tmpRenderable.RenderMethod !== 'virtual-assignment')\n\t\t{\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tthis.onAfterProjectAsync(fNext, tmpRenderable);\n\t\t\t});\n\n\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t{\n\t\t\t\tthis.onAfterRenderAsync(fNext, tmpRenderable);\n\t\t\t});\n\t\t}\n\n\t\ttmpAnticipate.wait(tmpCallback);\n\t}\n\n\t/**\n\t * Renders the default renderable.\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\trenderDefaultAsync(fCallback)\n\t{\n\t\t// Render the default renderable\n\t\tthis.renderAsync(fCallback);\n\t}\n\n\t/**\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbasicRender(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\treturn this.basicRenderWithScope(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t}\n\n\t/**\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t */\n\tbasicRenderWithScope(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)\n\t{\n\t\tlet tmpRenderOptions = this.buildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t\tif (tmpRenderOptions.Valid)\n\t\t{\n\t\t\tthis.assignRenderContent(tmpRenderOptions.Renderable, tmpRenderOptions.DestinationAddress, this.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash, tmpRenderOptions.Record, null, [this], pScope, { RootRenderable: tmpRenderOptions.Renderable }));\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not perform a basic render of ${tmpRenderOptions.RenderableHash} because it is not valid.`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t */\n\tbasicRenderAsync(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback)\n\t{\n\t\treturn this.basicRenderWithScopeAsync(this, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback);\n\t}\n\n\t/**\n\t * @param {any} pScope - The scope to use for the template rendering.\n\t * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.\n\t * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.\n\t * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.\n\t * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.\n\t */\n\tbasicRenderWithScopeAsync(pScope, pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress, fCallback)\n\t{\n\t\t// Allow the callback to be passed in as the last parameter no matter what\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback :\n\t\t\t\t\t\t\t(typeof(pTemplateRecordAddress) === 'function') ? pTemplateRecordAddress :\n\t\t\t\t\t\t\t(typeof(pRenderDestinationAddress) === 'function') ? pRenderDestinationAddress :\n\t\t\t\t\t\t\t(typeof(pRenderableHash) === 'function') ? pRenderableHash :\n\t\t\t\t\t\t\tnull;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} basicRenderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} basicRenderAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\tconst tmpRenderOptions = this.buildRenderOptions(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress);\n\t\tif (tmpRenderOptions.Valid)\n\t\t{\n\t\t\tthis.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash, tmpRenderOptions.Record,\n\t\t\t\t/**\n\t\t\t\t * @param {Error} [pError] - The error that occurred during template parsing.\n\t\t\t\t * @param {string} [pContent] - The content that was rendered from the template.\n\t\t\t\t */\n\t\t\t\t(pError, pContent) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not render (asynchronously) ${tmpRenderOptions.RenderableHash} because it did not parse the template.`, pError);\n\t\t\t\t\t\treturn tmpCallback(pError);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.assignRenderContent(tmpRenderOptions.Renderable, tmpRenderOptions.DestinationAddress, pContent);\n\t\t\t\t\treturn tmpCallback();\n\t\t\t\t}, [this], pScope, { RootRenderable: tmpRenderOptions.Renderable });\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpErrorMessage = `PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} could not perform a basic render of ${tmpRenderOptions.RenderableHash} because it is not valid.`;\n\t\t\tthis.log.error(tmpErrorMessage);\n\t\t\treturn tmpCallback(new Error(tmpErrorMessage));\n\t\t}\n\t}\n\n\t/**\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonProject(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onProject:`);\n\t\t}\n\t\tif (pRenderable.RenderMethod === 'virtual-assignment')\n\t\t{\n\t\t\tthis.pict.TransactionTracking.pushToTransactionQueue(pRenderable.TransactionHash, { ViewHash: this.Hash, Renderable: pRenderable }, 'Deferred-Post-Content-Assignment');\n\t\t}\n\n\t\tif (this.pict.LogNoisiness > 0)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} Assigning Renderable[${pRenderable.RenderableHash}] content length ${pRenderable.Content.length} to Destination [${pRenderable.ContentDestinationAddress}] using Async render method ${pRenderable.RenderMethod}.`);\n\t\t}\n\n\t\t// Assign the content to the destination address\n\t\tthis.pict.ContentAssignment.projectContent(pRenderable.RenderMethod, pRenderable.ContentDestinationAddress, pRenderable.Content, pRenderable.TestAddress);\n\n\t\tthis.lastRenderedTimestamp = this.pict.log.getTimeStamp();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM (async flow).\n\t *\n\t * @param {(error?: Error, content?: string) => void} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that is being projected.\n\t */\n\tonProjectAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onProject(pRenderable);\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is rendered.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonAfterRender(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRender:`);\n\t\t}\n\t\tif (pRenderable && pRenderable.RootRenderableViewHash === this.Hash)\n\t\t{\n\t\t\tconst tmpTransactionQueue = this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash) || [];\n\t\t\tfor (const tmpEvent of tmpTransactionQueue)\n\t\t\t{\n\t\t\t\tconst tmpView = this.pict.views[tmpEvent.Data.ViewHash];\n\t\t\t\tif (!tmpView)\n\t\t\t\t{\n\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRender: Could not find view for transaction hash ${pRenderable.TransactionHash} and ViewHash ${tmpEvent.Data.ViewHash}.`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttmpView.onAfterProject();\n\n\t\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\t\ttmpView.onAfterRender(tmpEvent.Data.Renderable);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is rendered (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that was rendered.\n\t */\n\tonAfterRenderAsync(fCallback, pRenderable)\n\t{\n\t\tthis.onAfterRender(pRenderable);\n\t\tconst tmpAnticipate = this.fable.newAnticipate();\n\t\tif (pRenderable && pRenderable.RootRenderableViewHash === this.Hash)\n\t\t{\n\t\t\tconst queue = this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash) || [];\n\t\t\tfor (const event of queue)\n\t\t\t{\n\t\t\t\t/** @type {PictView} */\n\t\t\t\tconst tmpView = this.pict.views[event.Data.ViewHash];\n\t\t\t\tif (!tmpView)\n\t\t\t\t{\n\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterRenderAsync: Could not find view for transaction hash ${pRenderable.TransactionHash} and ViewHash ${event.Data.ViewHash}.`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttmpAnticipate.anticipate(tmpView.onAfterProjectAsync.bind(tmpView));\n\t\t\t\ttmpAnticipate.anticipate((fNext) =>\n\t\t\t\t{\n\t\t\t\t\ttmpView.onAfterRenderAsync(fNext, event.Data.Renderable);\n\t\t\t\t});\n\n\t\t\t\t// Execute the developer-overridable post-render behavior\n\t\t\t}\n\t\t}\n\t\treturn tmpAnticipate.wait(fCallback);\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM.\n\t *\n\t * @param {Renderable} pRenderable - The renderable that was projected.\n\t */\n\tonAfterProject(pRenderable)\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterProject:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is projected into the DOM (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t * @param {Renderable} pRenderable - The renderable that was projected.\n\t */\n\tonAfterProjectAsync(fCallback, pRenderable)\n\t{\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Solver */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before the view is solved.\n\t */\n\tonBeforeSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeSolveAsync(fCallback)\n\t{\n\t\tthis.onBeforeSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is solved.\n\t */\n\tonSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonSolveAsync(fCallback)\n\t{\n\t\tthis.onSolve();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Performs view solving and triggers lifecycle hooks.\n\t *\n\t * @return {boolean} - True if the view was solved successfully, false otherwise.\n\t */\n\tsolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeSolve();\n\t\tthis.onSolve();\n\t\tthis.onAfterSolve();\n\t\tthis.lastSolvedTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Performs view solving and triggers lifecycle hooks (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tsolveAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} solveAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onSolveAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} solveAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastSolvedTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is solved.\n\t */\n\tonAfterSolve()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterSolve:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after the view is solved (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterSolveAsync(fCallback)\n\t{\n\t\tthis.onAfterSolve();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal From View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled from the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tonBeforeMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeMarshalFromViewAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled from the view.\n\t */\n\tonMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonMarshalFromViewAsync(fCallback)\n\t{\n\n\t\tthis.onMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Marshals data from the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tmarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeMarshalFromView();\n\t\tthis.onMarshalFromView();\n\t\tthis.onAfterMarshalFromView();\n\t\tthis.lastMarshalFromViewTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Marshals data from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tmarshalFromViewAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalFromViewAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalFromViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onMarshalFromViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalFromViewAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} marshalFromViewAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalFromViewTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled from the view.\n\t */\n\tonAfterMarshalFromView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterMarshalFromView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled from the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterMarshalFromViewAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalFromView();\n\t\treturn fCallback();\n\t}\n\n\t/* -------------------------------------------------------------------------- */\n\t/* Code Section: Marshal To View */\n\t/* -------------------------------------------------------------------------- */\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled into the view.\n\t */\n\tonBeforeMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onBeforeMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers before data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonBeforeMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onBeforeMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled into the view.\n\t */\n\tonMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers when data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/**\n\t * Marshals data into the view.\n\t *\n\t * @return {boolean} - True if the operation was successful, false otherwise.\n\t */\n\tmarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 2)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} executing solve() function...`);\n\t\t}\n\t\tthis.onBeforeMarshalToView();\n\t\tthis.onMarshalToView();\n\t\tthis.onAfterMarshalToView();\n\t\tthis.lastMarshalToViewTimestamp = this.pict.log.getTimeStamp();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Marshals data into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tmarshalToViewAsync(fCallback)\n\t{\n\t\tlet tmpAnticipate = this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');\n\n\n\t\t/** @type {ErrorCallback} */\n\t\tlet tmpCallback = (typeof(fCallback) === 'function') ? fCallback : null;\n\t\tif (!tmpCallback)\n\t\t{\n\t\t\tthis.log.warn(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions.`);\n\t\t\ttmpCallback = (pError) =>\n\t\t\t\t{\n\t\t\t\t\tif (pError)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.log.error(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.Name} marshalToViewAsync Auto Callback Error: ${pError}`, pError);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t}\n\t\ttmpAnticipate.anticipate(this.onBeforeMarshalToViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onMarshalToViewAsync.bind(this));\n\t\ttmpAnticipate.anticipate(this.onAfterMarshalToViewAsync.bind(this));\n\n\t\ttmpAnticipate.wait(\n\t\t\t(pError) =>\n\t\t\t{\n\t\t\t\tif (this.pict.LogNoisiness > 2)\n\t\t\t\t{\n\t\t\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} marshalToViewAsync() complete.`);\n\t\t\t\t}\n\t\t\t\tthis.lastMarshalToViewTimestamp = this.pict.log.getTimeStamp();\n\t\t\t\treturn tmpCallback(pError);\n\t\t\t});\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled into the view.\n\t */\n\tonAfterMarshalToView()\n\t{\n\t\tif (this.pict.LogNoisiness > 3)\n\t\t{\n\t\t\tthis.log.trace(`PictView [${this.UUID}]::[${this.Hash}] ${this.options.ViewIdentifier} onAfterMarshalToView:`);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Lifecycle hook that triggers after data is marshaled into the view (async flow).\n\t *\n\t * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.\n\t */\n\tonAfterMarshalToViewAsync(fCallback)\n\t{\n\t\tthis.onAfterMarshalToView();\n\t\treturn fCallback();\n\t}\n\n\t/** @return {boolean} - True if the object is a PictView. */\n\tget isPictView()\n\t{\n\t\treturn true;\n\t}\n}\n\nmodule.exports = PictView;\n","// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n","module.exports={\n\t\"Name\": \"Retold Data Cloner\",\n\t\"Hash\": \"DataCloner\",\n\t\"MainViewportViewIdentifier\": \"DataCloner-Layout\",\n\t\"MainViewportDestinationAddress\": \"#DataCloner-Application-Container\",\n\t\"MainViewportDefaultDataAddress\": \"AppData.DataCloner\",\n\t\"pict_configuration\": { \"Product\": \"DataCloner\" },\n\t\"AutoRenderMainViewportViewAfterInitialize\": false\n}\n","const libPictApplication = require('pict-application');\n\nconst libProvider = require('./providers/Pict-Provider-DataCloner.js');\n\nconst libViewLayout = require('./views/PictView-DataCloner-Layout.js');\nconst libViewConnection = require('./views/PictView-DataCloner-Connection.js');\nconst libViewSession = require('./views/PictView-DataCloner-Session.js');\nconst libViewSchema = require('./views/PictView-DataCloner-Schema.js');\nconst libViewDeploy = require('./views/PictView-DataCloner-Deploy.js');\nconst libViewSync = require('./views/PictView-DataCloner-Sync.js');\nconst libViewExport = require('./views/PictView-DataCloner-Export.js');\nconst libViewViewData = require('./views/PictView-DataCloner-ViewData.js');\nconst libViewHistogram = require('pict-section-histogram');\n\nclass DataClonerApplication extends libPictApplication\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\n\t\t// Register provider\n\t\tthis.pict.addProvider('DataCloner', libProvider.default_configuration, libProvider);\n\n\t\t// Register views\n\t\tthis.pict.addView('DataCloner-Layout', libViewLayout.default_configuration, libViewLayout);\n\t\tthis.pict.addView('DataCloner-Connection', libViewConnection.default_configuration, libViewConnection);\n\t\tthis.pict.addView('DataCloner-Session', libViewSession.default_configuration, libViewSession);\n\t\tthis.pict.addView('DataCloner-Schema', libViewSchema.default_configuration, libViewSchema);\n\t\tthis.pict.addView('DataCloner-Deploy', libViewDeploy.default_configuration, libViewDeploy);\n\t\tthis.pict.addView('DataCloner-Sync', libViewSync.default_configuration, libViewSync);\n\t\tthis.pict.addView('DataCloner-Export', libViewExport.default_configuration, libViewExport);\n\t\tthis.pict.addView('DataCloner-ViewData', libViewViewData.default_configuration, libViewViewData);\n\t\tthis.pict.addView('DataCloner-StatusHistogram',\n\t\t\t{\n\t\t\t\tViewIdentifier: 'DataCloner-StatusHistogram',\n\t\t\t\tTargetElementAddress: '#DataCloner-Throughput-Histogram',\n\t\t\t\tDefaultDestinationAddress: '#DataCloner-Throughput-Histogram',\n\t\t\t\tRenderOnLoad: false,\n\t\t\t\tSelectable: false,\n\t\t\t\tOrientation: 'vertical',\n\t\t\t\tFillContainer: true,\n\t\t\t\tShowValues: false,\n\t\t\t\tShowLabels: true,\n\t\t\t\tMaxBarSize: 80,\n\t\t\t\tBarColor: '#4a90d9',\n\t\t\t\tBins: []\n\t\t\t}, libViewHistogram);\n\t}\n\n\tonAfterInitializeAsync(fCallback)\n\t{\n\t\t// Centralized state (replaces global variables)\n\t\tthis.pict.AppData.DataCloner =\n\t\t{\n\t\t\tFetchedTables: [],\n\t\t\tDeployedTables: [],\n\t\t\tLastReport: null,\n\t\t\tServerBusyAtLoad: false,\n\t\t\tSyncPollTimer: null,\n\t\t\tLiveStatusTimer: null,\n\t\t\tStatusDetailExpanded: false,\n\t\t\tStatusDetailAutoExpanded: false,\n\t\t\tStatusDetailTimer: null,\n\t\t\tStatusDetailData: null,\n\t\t\tLastLiveStatus: null,\n\t\t\tPersistFields: [\n\t\t\t\t'serverURL', 'authMethod', 'authURI', 'checkURI',\n\t\t\t\t'cookieName', 'cookieValueAddr', 'cookieValueTemplate', 'loginMarker',\n\t\t\t\t'userName', 'password', 'schemaURL', 'pageSize', 'dateTimePrecisionMS',\n\t\t\t\t'connProvider', 'sqliteFilePath',\n\t\t\t\t'mysqlServer', 'mysqlPort', 'mysqlUser', 'mysqlPassword', 'mysqlDatabase', 'mysqlConnectionLimit',\n\t\t\t\t'mssqlServer', 'mssqlPort', 'mssqlUser', 'mssqlPassword', 'mssqlDatabase', 'mssqlConnectionLimit',\n\t\t\t\t'postgresqlHost', 'postgresqlPort', 'postgresqlUser', 'postgresqlPassword', 'postgresqlDatabase', 'postgresqlConnectionLimit',\n\t\t\t\t'solrHost', 'solrPort', 'solrCore', 'solrPath',\n\t\t\t\t'mongodbHost', 'mongodbPort', 'mongodbUser', 'mongodbPassword', 'mongodbDatabase', 'mongodbConnectionLimit',\n\t\t\t\t'rocksdbFolder',\n\t\t\t\t'bibliographFolder',\n\t\t\t\t'syncMaxRecords'\n\t\t\t]\n\t\t};\n\n\t\t// Make pict available for inline onclick handlers\n\t\twindow.pict = this.pict;\n\n\t\t// Render layout (which chains child view renders via onAfterRender)\n\t\tthis.pict.views['DataCloner-Layout'].render();\n\n\t\t// Post-render initialization\n\t\tthis.pict.providers.DataCloner.initPersistence();\n\t\tthis.pict.views['DataCloner-Connection'].onProviderChange();\n\t\tthis.pict.providers.DataCloner.restoreDeployedTables();\n\t\tthis.pict.providers.DataCloner.startLiveStatusPolling();\n\t\tthis.pict.providers.DataCloner.initAccordionPreviews();\n\t\tthis.pict.providers.DataCloner.updateAllPreviews();\n\t\tthis.pict.views['DataCloner-Layout'].collapseAllSections();\n\t\tthis.pict.providers.DataCloner.initAutoProcess();\n\n\t\treturn fCallback();\n\t}\n}\n\nmodule.exports = DataClonerApplication;\n\nmodule.exports.default_configuration = require('./Pict-Application-DataCloner-Configuration.json');\n","module.exports = { DataClonerApplication: require('./Pict-Application-DataCloner.js') };\n\nif (typeof(window) !== 'undefined')\n{\n\twindow.DataClonerApplication = module.exports.DataClonerApplication;\n}\n","const libPictProvider = require('pict-provider');\n\nclass DataClonerProvider extends libPictProvider\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\t// ================================================================\n\t// API Helper\n\t// ================================================================\n\n\tapi(pMethod, pPath, pBody)\n\t{\n\t\tlet tmpOpts = { method: pMethod, headers: {} };\n\t\tif (pBody)\n\t\t{\n\t\t\ttmpOpts.headers['Content-Type'] = 'application/json';\n\t\t\ttmpOpts.body = JSON.stringify(pBody);\n\t\t}\n\t\treturn fetch(pPath, tmpOpts).then(function(pResponse) { return pResponse.json(); });\n\t}\n\n\tsetStatus(pElementId, pMessage, pType)\n\t{\n\t\tlet tmpEl = document.getElementById(pElementId);\n\t\tif (!tmpEl) return;\n\t\ttmpEl.className = 'status ' + (pType || 'info');\n\t\ttmpEl.textContent = pMessage;\n\t\ttmpEl.style.display = 'block';\n\t}\n\n\tescapeHtml(pStr)\n\t{\n\t\tlet tmpDiv = document.createElement('div');\n\t\ttmpDiv.appendChild(document.createTextNode(pStr));\n\t\treturn tmpDiv.innerHTML;\n\t}\n\n\t// ================================================================\n\t// Phase status indicators\n\t// ================================================================\n\n\tsetSectionPhase(pSection, pState)\n\t{\n\t\tlet tmpEl = document.getElementById('phase' + pSection);\n\t\tif (!tmpEl) return;\n\n\t\ttmpEl.className = 'accordion-phase';\n\n\t\tif (pState === 'ok')\n\t\t{\n\t\t\ttmpEl.innerHTML = '✓';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-ok');\n\t\t}\n\t\telse if (pState === 'error')\n\t\t{\n\t\t\ttmpEl.innerHTML = '✗';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-error');\n\t\t}\n\t\telse if (pState === 'busy')\n\t\t{\n\t\t\ttmpEl.innerHTML = '<span class=\"phase-spinner\"></span>';\n\t\t\ttmpEl.classList.add('visible', 'accordion-phase-busy');\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpEl.innerHTML = '';\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Accordion Previews\n\t// ================================================================\n\n\tupdateAllPreviews()\n\t{\n\t\t// Section 1 — Database Connection\n\t\tlet tmpProvider = document.getElementById('connProvider');\n\t\tif (!tmpProvider) return;\n\t\ttmpProvider = tmpProvider.value;\n\t\tlet tmpPreview1 = tmpProvider;\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\tlet tmpPath = document.getElementById('sqliteFilePath').value || '~/headlight-liveconnect-local/cloned.sqlite';\n\t\t\ttmpPreview1 = 'SQLite at ' + tmpPath;\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mysqlServer').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mysqlPort').value || '3306';\n\t\t\tlet tmpUser = document.getElementById('mysqlUser').value || 'root';\n\t\t\ttmpPreview1 = 'MySQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mssqlServer').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mssqlPort').value || '1433';\n\t\t\tlet tmpUser = document.getElementById('mssqlUser').value || 'sa';\n\t\t\ttmpPreview1 = 'MSSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('postgresqlHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('postgresqlPort').value || '5432';\n\t\t\tlet tmpUser = document.getElementById('postgresqlUser').value || 'postgres';\n\t\t\ttmpPreview1 = 'PostgreSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;\n\t\t}\n\t\telse if (tmpProvider === 'MongoDB')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('mongodbHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('mongodbPort').value || '27017';\n\t\t\ttmpPreview1 = 'MongoDB on ' + tmpHost + ':' + tmpPort;\n\t\t}\n\t\telse if (tmpProvider === 'Solr')\n\t\t{\n\t\t\tlet tmpHost = document.getElementById('solrHost').value || '127.0.0.1';\n\t\t\tlet tmpPort = document.getElementById('solrPort').value || '8983';\n\t\t\ttmpPreview1 = 'Solr on ' + tmpHost + ':' + tmpPort;\n\t\t}\n\t\telse if (tmpProvider === 'RocksDB')\n\t\t{\n\t\t\tlet tmpFolder = document.getElementById('rocksdbFolder').value || '~/headlight-liveconnect-local/rocksdb';\n\t\t\ttmpPreview1 = 'RocksDB at ' + tmpFolder;\n\t\t}\n\t\telse if (tmpProvider === 'Bibliograph')\n\t\t{\n\t\t\tlet tmpFolder = document.getElementById('bibliographFolder').value || '~/headlight-liveconnect-local/bibliograph';\n\t\t\ttmpPreview1 = 'Bibliograph at ' + tmpFolder;\n\t\t}\n\t\tdocument.getElementById('preview1').textContent = tmpPreview1;\n\n\t\t// Section 2 — Remote Session\n\t\tlet tmpServerURL = document.getElementById('serverURL').value;\n\t\tlet tmpUserName = document.getElementById('userName').value;\n\t\tif (tmpServerURL)\n\t\t{\n\t\t\tlet tmpPreview2 = tmpServerURL;\n\t\t\tif (tmpUserName) tmpPreview2 += ' as ' + tmpUserName;\n\t\t\tdocument.getElementById('preview2').textContent = tmpPreview2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview2').textContent = 'Configure remote server URL and credentials';\n\t\t}\n\n\t\t// Section 3 — Remote Schema\n\t\tlet tmpTableChecks = document.querySelectorAll('#tableList input[type=\"checkbox\"]:checked');\n\t\tif (tmpTableChecks.length > 0)\n\t\t{\n\t\t\tdocument.getElementById('preview3').textContent = tmpTableChecks.length + ' table' + (tmpTableChecks.length === 1 ? '' : 's') + ' selected';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value;\n\t\t\tif (tmpSchemaURL)\n\t\t\t{\n\t\t\t\tdocument.getElementById('preview3').textContent = 'Schema from ' + tmpSchemaURL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById('preview3').textContent = 'Fetch and select tables from the remote server';\n\t\t\t}\n\t\t}\n\n\t\t// Section 4 — Deploy Schema\n\t\tlet tmpDeployedEl = document.getElementById('deployStatus');\n\t\tlet tmpDeployedText = tmpDeployedEl ? tmpDeployedEl.textContent : '';\n\t\tif (tmpDeployedText && tmpDeployedText.indexOf('deployed') !== -1)\n\t\t{\n\t\t\tdocument.getElementById('preview4').textContent = tmpDeployedText;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview4').textContent = 'Create selected tables in the local database';\n\t\t}\n\n\t\t// Section 5 — Synchronize Data\n\t\tlet tmpSyncMode = document.querySelector('input[name=\"syncMode\"]:checked');\n\t\tlet tmpModeName = tmpSyncMode ? tmpSyncMode.value : 'Initial';\n\t\tlet tmpPageSize = document.getElementById('pageSize').value || '100';\n\t\tlet tmpSyncPreview = tmpModeName + ' sync, page size ' + tmpPageSize;\n\t\tlet tmpDeleted = document.getElementById('syncDeletedRecords').checked;\n\t\tif (tmpDeleted) tmpSyncPreview += ', including deleted';\n\t\tdocument.getElementById('preview5').textContent = tmpSyncPreview;\n\n\t\t// Section 6 — Export Configuration\n\t\tlet tmpMaxRecords = document.getElementById('syncMaxRecords').value;\n\t\tlet tmpLogFile = document.getElementById('syncLogFile').checked;\n\t\tlet tmpExportParts = [];\n\t\tif (tmpMaxRecords && parseInt(tmpMaxRecords, 10) > 0) tmpExportParts.push('max ' + tmpMaxRecords + ' records');\n\t\tif (tmpLogFile) tmpExportParts.push('log enabled');\n\t\telse tmpExportParts.push('log disabled');\n\t\tdocument.getElementById('preview6').textContent = tmpExportParts.length > 0 ? 'Export: ' + tmpExportParts.join(', ') : 'Generate JSON config for headless cloning';\n\n\t\t// Section 7 — View Data\n\t\tlet tmpViewTable = document.getElementById('viewTable').value;\n\t\tif (tmpViewTable)\n\t\t{\n\t\t\tdocument.getElementById('preview7').textContent = 'Viewing ' + tmpViewTable;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdocument.getElementById('preview7').textContent = 'Browse synced table data';\n\t\t}\n\t}\n\n\tinitAccordionPreviews()\n\t{\n\t\tlet tmpSelf = this;\n\n\t\tlet tmpPreviewFields = [\n\t\t\t'connProvider', 'sqliteFilePath',\n\t\t\t'mysqlServer', 'mysqlPort', 'mysqlUser',\n\t\t\t'mssqlServer', 'mssqlPort', 'mssqlUser',\n\t\t\t'postgresqlHost', 'postgresqlPort', 'postgresqlUser',\n\t\t\t'mongodbHost', 'mongodbPort',\n\t\t\t'solrHost', 'solrPort',\n\t\t\t'rocksdbFolder', 'bibliographFolder',\n\t\t\t'serverURL', 'userName',\n\t\t\t'schemaURL',\n\t\t\t'pageSize', 'dateTimePrecisionMS',\n\t\t\t'syncMaxRecords',\n\t\t\t'viewTable', 'viewLimit'\n\t\t];\n\n\t\tlet tmpHandler = function() { tmpSelf.updateAllPreviews(); };\n\n\t\tfor (let i = 0; i < tmpPreviewFields.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById(tmpPreviewFields[i]);\n\t\t\tif (tmpEl)\n\t\t\t{\n\t\t\t\ttmpEl.addEventListener('input', tmpHandler);\n\t\t\t\ttmpEl.addEventListener('change', tmpHandler);\n\t\t\t}\n\t\t}\n\n\t\t// Checkboxes and radios\n\t\tlet tmpCheckboxes = ['syncDeletedRecords', 'syncLogFile'];\n\t\tfor (let i = 0; i < tmpCheckboxes.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById(tmpCheckboxes[i]);\n\t\t\tif (tmpEl) tmpEl.addEventListener('change', tmpHandler);\n\t\t}\n\n\t\tdocument.querySelectorAll('input[name=\"syncMode\"]').forEach(function(pEl)\n\t\t{\n\t\t\tpEl.addEventListener('change', tmpHandler);\n\t\t});\n\t}\n\n\t// ================================================================\n\t// LocalStorage Persistence\n\t// ================================================================\n\n\tsaveField(pFieldId)\n\t{\n\t\tlet tmpEl = document.getElementById(pFieldId);\n\t\tif (tmpEl)\n\t\t{\n\t\t\tlocalStorage.setItem('dataCloner_' + pFieldId, tmpEl.value);\n\t\t}\n\t}\n\n\trestoreFields()\n\t{\n\t\tlet tmpPersistFields = this.pict.AppData.DataCloner.PersistFields;\n\t\tfor (let i = 0; i < tmpPersistFields.length; i++)\n\t\t{\n\t\t\tlet tmpId = tmpPersistFields[i];\n\t\t\tlet tmpSaved = localStorage.getItem('dataCloner_' + tmpId);\n\t\t\tif (tmpSaved !== null)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(tmpId);\n\t\t\t\tif (tmpEl) tmpEl.value = tmpSaved;\n\t\t\t}\n\t\t}\n\n\t\t// Restore checkbox state\n\t\tlet tmpSyncDeleted = localStorage.getItem('dataCloner_syncDeletedRecords');\n\t\tif (tmpSyncDeleted !== null)\n\t\t{\n\t\t\tdocument.getElementById('syncDeletedRecords').checked = tmpSyncDeleted === 'true';\n\t\t}\n\t\t// Restore sync mode\n\t\tlet tmpSyncMode = localStorage.getItem('dataCloner_syncMode');\n\t\tif (tmpSyncMode === 'Ongoing')\n\t\t{\n\t\t\tdocument.getElementById('syncModeOngoing').checked = true;\n\t\t}\n\t\tlet tmpSolrSecure = localStorage.getItem('dataCloner_solrSecure');\n\t\tif (tmpSolrSecure !== null)\n\t\t{\n\t\t\tdocument.getElementById('solrSecure').checked = tmpSolrSecure === 'true';\n\t\t}\n\t\t// Restore advanced ID pagination checkbox\n\t\tlet tmpAdvancedIDPagination = localStorage.getItem('dataCloner_syncAdvancedIDPagination');\n\t\tif (tmpAdvancedIDPagination !== null)\n\t\t{\n\t\t\tdocument.getElementById('syncAdvancedIDPagination').checked = tmpAdvancedIDPagination === 'true';\n\t\t}\n\t}\n\n\tinitPersistence()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.restoreFields();\n\n\t\tlet tmpPersistFields = this.pict.AppData.DataCloner.PersistFields;\n\t\tfor (let i = 0; i < tmpPersistFields.length; i++)\n\t\t{\n\t\t\t(function(pId)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(pId);\n\t\t\t\tif (tmpEl)\n\t\t\t\t{\n\t\t\t\t\ttmpEl.addEventListener('input', function() { tmpSelf.saveField(pId); });\n\t\t\t\t\ttmpEl.addEventListener('change', function() { tmpSelf.saveField(pId); });\n\t\t\t\t}\n\t\t\t})(tmpPersistFields[i]);\n\t\t}\n\n\t\t// Persist sync deleted checkbox\n\t\tlet tmpSyncDeletedEl = document.getElementById('syncDeletedRecords');\n\t\tif (tmpSyncDeletedEl)\n\t\t{\n\t\t\ttmpSyncDeletedEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncDeletedRecords', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist sync mode radio\n\t\tdocument.querySelectorAll('input[name=\"syncMode\"]').forEach(function(pEl)\n\t\t{\n\t\t\tpEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncMode', this.value);\n\t\t\t});\n\t\t});\n\n\t\t// Persist solr secure checkbox\n\t\tlet tmpSolrSecureEl = document.getElementById('solrSecure');\n\t\tif (tmpSolrSecureEl)\n\t\t{\n\t\t\ttmpSolrSecureEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_solrSecure', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist advanced ID pagination checkbox\n\t\tlet tmpAdvancedIDPaginationEl = document.getElementById('syncAdvancedIDPagination');\n\t\tif (tmpAdvancedIDPaginationEl)\n\t\t{\n\t\t\ttmpAdvancedIDPaginationEl.addEventListener('change', function()\n\t\t\t{\n\t\t\t\tlocalStorage.setItem('dataCloner_syncAdvancedIDPagination', this.checked);\n\t\t\t});\n\t\t}\n\n\t\t// Persist auto-process checkboxes\n\t\tlet tmpAutoIds = ['auto1', 'auto2', 'auto3', 'auto4', 'auto5'];\n\t\tfor (let a = 0; a < tmpAutoIds.length; a++)\n\t\t{\n\t\t\t(function(pId)\n\t\t\t{\n\t\t\t\tlet tmpEl = document.getElementById(pId);\n\t\t\t\tif (tmpEl)\n\t\t\t\t{\n\t\t\t\t\tlet tmpSaved = localStorage.getItem('dataCloner_' + pId);\n\t\t\t\t\tif (tmpSaved !== null) tmpEl.checked = tmpSaved === 'true';\n\t\t\t\t\ttmpEl.addEventListener('change', function()\n\t\t\t\t\t{\n\t\t\t\t\t\tlocalStorage.setItem('dataCloner_' + pId, this.checked);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})(tmpAutoIds[a]);\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Live Status Indicator\n\t// ================================================================\n\n\tstartLiveStatusPolling()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\tif (tmpAppData.LiveStatusTimer) clearInterval(tmpAppData.LiveStatusTimer);\n\t\tthis.pollLiveStatus();\n\t\tlet tmpSelf = this;\n\t\ttmpAppData.LiveStatusTimer = setInterval(function() { tmpSelf.pollLiveStatus(); }, 1500);\n\t}\n\n\tpollLiveStatus()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/live-status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.renderLiveStatus(pData);\n\t\t\t})\n\t\t\t.catch(function()\n\t\t\t{\n\t\t\t\ttmpSelf.renderLiveStatus({ Phase: 'disconnected', Message: 'Cannot reach server', TotalSynced: 0, TotalRecords: 0 });\n\t\t\t});\n\t}\n\n\trenderLiveStatus(pData)\n\t{\n\t\t// Cache the live status data for the detail view\n\t\tthis.pict.AppData.DataCloner.LastLiveStatus = pData;\n\n\t\tlet tmpBar = document.getElementById('liveStatusBar');\n\t\tlet tmpMsg = document.getElementById('liveStatusMessage');\n\t\tlet tmpMeta = document.getElementById('liveStatusMeta');\n\t\tlet tmpProgressFill = document.getElementById('liveStatusProgressFill');\n\t\tif (!tmpBar) return;\n\n\t\t// Update phase class (preserve expanded class if present)\n\t\tlet tmpWasExpanded = tmpBar.classList.contains('expanded');\n\t\ttmpBar.className = 'live-status-bar phase-' + (pData.Phase || 'idle');\n\t\tif (tmpWasExpanded) tmpBar.classList.add('expanded');\n\n\t\t// Update message\n\t\ttmpMsg.textContent = pData.Message || 'Idle';\n\n\t\t// Update meta info\n\t\tlet tmpMetaParts = [];\n\t\tif (pData.Phase === 'syncing' || pData.Phase === 'stopping')\n\t\t{\n\t\t\tif (pData.Elapsed)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + pData.Elapsed + '</span>');\n\t\t\t}\n\t\t\tif (pData.ETA)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">~' + pData.ETA + ' remaining</span>');\n\t\t\t}\n\t\t\tif (pData.TotalTables > 0)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + pData.Completed + '</strong> / ' + pData.TotalTables + ' tables</span>');\n\t\t\t}\n\t\t\tif (pData.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = pData.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\tif (pData.PreCountGrandTotal > 0)\n\t\t\t\t{\n\t\t\t\t\tlet tmpGrandTotal = pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> / ' + tmpGrandTotal + ' records</span>');\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (pData.PreCountGrandTotal > 0)\n\t\t\t{\n\t\t\t\tlet tmpGrandTotal = pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">' + tmpGrandTotal + ' records to sync</span>');\n\t\t\t}\n\t\t\tif (pData.PreCountProgress && pData.PreCountProgress.Counted < pData.PreCountProgress.TotalTables)\n\t\t\t{\n\t\t\t\tlet tmpCountedSoFar = pData.PreCountGrandTotal > 0\n\t\t\t\t\t? ' (' + pData.PreCountGrandTotal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + ' records found)'\n\t\t\t\t\t: '';\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\">counting: ' + pData.PreCountProgress.Counted + ' / ' + pData.PreCountProgress.TotalTables + ' tables' + tmpCountedSoFar + '</span>');\n\t\t\t}\n\t\t\tif (pData.Errors > 0)\n\t\t\t{\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\" style=\"color:#dc3545\"><strong>' + pData.Errors + '</strong> error' + (pData.Errors === 1 ? '' : 's') + '</span>');\n\t\t\t}\n\t\t}\n\t\telse if (pData.Phase === 'complete')\n\t\t{\n\t\t\tif (pData.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = pData.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\ttmpMetaParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records synced</span>');\n\t\t\t}\n\t\t}\n\t\ttmpMeta.innerHTML = tmpMetaParts.join('');\n\n\t\t// Update progress bar\n\t\tlet tmpPct = 0;\n\t\tif (pData.Phase === 'syncing' && pData.PreCountProgress && pData.PreCountProgress.Counted < pData.PreCountProgress.TotalTables)\n\t\t{\n\t\t\t// During counting phase, show table counting progress\n\t\t\ttmpPct = Math.min((pData.PreCountProgress.Counted / pData.PreCountProgress.TotalTables) * 100, 99);\n\t\t}\n\t\telse if (pData.Phase === 'syncing' && pData.PreCountGrandTotal > 0 && pData.TotalSynced > 0)\n\t\t{\n\t\t\ttmpPct = Math.min((pData.TotalSynced / pData.PreCountGrandTotal) * 100, 99.9);\n\t\t}\n\t\telse if (pData.Phase === 'syncing' && pData.TotalTables > 0)\n\t\t{\n\t\t\tlet tmpTablePct = (pData.Completed / pData.TotalTables) * 100;\n\t\t\tif (pData.ActiveProgress && pData.ActiveProgress.Total > 0)\n\t\t\t{\n\t\t\t\tlet tmpEntityPct = (pData.ActiveProgress.Synced / pData.ActiveProgress.Total) * (100 / pData.TotalTables);\n\t\t\t\ttmpPct = tmpTablePct + tmpEntityPct;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpPct = tmpTablePct;\n\t\t\t}\n\t\t}\n\t\telse if (pData.Phase === 'complete')\n\t\t{\n\t\t\ttmpPct = 100;\n\t\t}\n\t\ttmpProgressFill.style.width = Math.min(100, Math.round(tmpPct)) + '%';\n\n\t\t// Auto-expand the detail view once when sync first starts so users see counting progress.\n\t\t// Only expand once per sync run — if the user collapses it, respect that choice.\n\t\tif ((pData.Phase === 'syncing' || pData.Phase === 'stopping') && !this.pict.AppData.DataCloner.StatusDetailExpanded && !this.pict.AppData.DataCloner.StatusDetailAutoExpanded)\n\t\t{\n\t\t\tthis.pict.AppData.DataCloner.StatusDetailAutoExpanded = true;\n\t\t\tlet tmpLayoutView = this.pict.views['DataCloner-Layout'];\n\t\t\tif (tmpLayoutView && typeof tmpLayoutView.toggleStatusDetail === 'function')\n\t\t\t{\n\t\t\t\ttmpLayoutView.toggleStatusDetail();\n\t\t\t}\n\t\t}\n\n\t\t// Reset the auto-expand flag when the sync is no longer running,\n\t\t// so the next sync run will auto-expand again.\n\t\tif (pData.Phase !== 'syncing' && pData.Phase !== 'stopping')\n\t\t{\n\t\t\tthis.pict.AppData.DataCloner.StatusDetailAutoExpanded = false;\n\t\t}\n\n\t\t// If the detail view is expanded, re-render it with fresh data\n\t\tif (this.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t{\n\t\t\tthis.renderStatusDetail();\n\t\t}\n\n\t\t// Auto-fetch the sync report when we detect a completed sync but haven't loaded the report yet\n\t\tif (pData.Phase === 'complete' && !this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tlet tmpSelf = this;\n\t\t\tthis.api('GET', '/clone/sync/report')\n\t\t\t\t.then(function(pReportData)\n\t\t\t\t{\n\t\t\t\t\tif (pReportData && pReportData.ReportVersion)\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.LastReport = pReportData;\n\t\t\t\t\t\tif (tmpSelf.pict.AppData.DataCloner.StatusDetailExpanded)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.renderStatusDetail();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch(function() { /* ignore fetch errors */ });\n\t\t}\n\t}\n\n\t// ================================================================\n\t// Status Detail Expansion\n\t// ================================================================\n\n\tonStatusDetailExpanded()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\ttmpAppData.StatusDetailExpanded = true;\n\n\t\t// Immediate render from whatever data we have\n\t\tthis.renderStatusDetail();\n\n\t\t// Start detail polling (poll /sync/status for per-table data)\n\t\tif (tmpAppData.StatusDetailTimer) clearInterval(tmpAppData.StatusDetailTimer);\n\t\tlet tmpSelf = this;\n\t\ttmpAppData.StatusDetailTimer = setInterval(function() { tmpSelf.pollStatusDetail(); }, 2000);\n\t\tthis.pollStatusDetail();\n\t}\n\n\tonStatusDetailCollapsed()\n\t{\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\ttmpAppData.StatusDetailExpanded = false;\n\n\t\tif (tmpAppData.StatusDetailTimer)\n\t\t{\n\t\t\tclearInterval(tmpAppData.StatusDetailTimer);\n\t\t\ttmpAppData.StatusDetailTimer = null;\n\t\t}\n\t}\n\n\tpollStatusDetail()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.AppData.DataCloner.StatusDetailData = pData;\n\t\t\t\ttmpSelf.renderStatusDetail();\n\t\t\t})\n\t\t\t.catch(function() { /* ignore poll errors */ });\n\t}\n\n\trenderCountingPhaseDetail(pContainer, pPreCountProgress)\n\t{\n\t\tlet tmpTables = pPreCountProgress.Tables || [];\n\t\tlet tmpCounted = pPreCountProgress.Counted || 0;\n\t\tlet tmpTotal = pPreCountProgress.TotalTables || 0;\n\t\tlet tmpRunningTotal = 0;\n\n\t\tlet tmpHtml = '<div class=\"status-detail-section\">';\n\t\ttmpHtml += '<div class=\"status-detail-section-title\">Counting Records (' + tmpCounted + ' / ' + tmpTotal + ' tables)</div>';\n\n\t\tif (tmpTables.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<table class=\"precount-table\">';\n\t\t\ttmpHtml += '<thead><tr><th>Table</th><th style=\"text-align:right\">Records</th><th style=\"text-align:right\">Time</th></tr></thead>';\n\t\t\ttmpHtml += '<tbody>';\n\t\t\tfor (let i = 0; i < tmpTables.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpT = tmpTables[i];\n\t\t\t\ttmpRunningTotal += tmpT.Count;\n\t\t\t\tlet tmpCountFmt = this.formatNumber(tmpT.Count);\n\t\t\t\tlet tmpTimeFmt = tmpT.ElapsedMs < 1000\n\t\t\t\t\t? tmpT.ElapsedMs + 'ms'\n\t\t\t\t\t: (tmpT.ElapsedMs / 1000).toFixed(1) + 's';\n\t\t\t\tlet tmpRowClass = tmpT.Error ? ' class=\"precount-error\"' : '';\n\t\t\t\ttmpHtml += '<tr' + tmpRowClass + '>';\n\t\t\t\ttmpHtml += '<td>' + this.escapeHtml(tmpT.Name) + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums\">' + tmpCountFmt + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums; color:#888\">' + tmpTimeFmt + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</tbody>';\n\t\t\ttmpHtml += '<tfoot><tr>';\n\t\t\ttmpHtml += '<td><strong>Total</strong></td>';\n\t\t\ttmpHtml += '<td style=\"text-align:right; font-variant-numeric:tabular-nums\"><strong>' + this.formatNumber(tmpRunningTotal) + '</strong></td>';\n\t\t\ttmpHtml += '<td></td>';\n\t\t\ttmpHtml += '</tr></tfoot>';\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// Show pending indicator for remaining tables\n\t\tlet tmpRemaining = tmpTotal - tmpCounted;\n\t\tif (tmpRemaining > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"precount-pending\">';\n\t\t\ttmpHtml += '<span class=\"precount-spinner\"></span> ';\n\t\t\ttmpHtml += tmpRemaining + ' table' + (tmpRemaining === 1 ? '' : 's') + ' remaining…';\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\tpContainer.innerHTML = tmpHtml;\n\t}\n\n\trenderStatusDetail()\n\t{\n\t\tlet tmpContainer = document.getElementById('DataCloner-StatusDetail-Container');\n\t\tif (!tmpContainer) return;\n\n\t\tlet tmpAppData = this.pict.AppData.DataCloner;\n\t\tlet tmpLiveStatus = tmpAppData.LastLiveStatus;\n\t\tlet tmpStatusData = tmpAppData.StatusDetailData;\n\t\tlet tmpReport = tmpAppData.LastReport;\n\n\t\t// During the counting phase, show per-table counts as they arrive\n\t\tif (tmpLiveStatus && tmpLiveStatus.PreCountProgress\n\t\t\t&& tmpLiveStatus.PreCountProgress.Tables\n\t\t\t&& tmpLiveStatus.Phase === 'syncing'\n\t\t\t&& tmpLiveStatus.PreCountProgress.Counted < tmpLiveStatus.PreCountProgress.TotalTables)\n\t\t{\n\t\t\tthis.renderCountingPhaseDetail(tmpContainer, tmpLiveStatus.PreCountProgress);\n\t\t\t// Prepend the summary banner above the counting detail\n\t\t\tlet tmpSummaryBanner = this.buildStatusSummaryHtml();\n\t\t\tif (tmpSummaryBanner)\n\t\t\t{\n\t\t\t\ttmpContainer.innerHTML = tmpSummaryBanner + tmpContainer.innerHTML;\n\t\t\t}\n\t\t\t// Hide histogram during counting\n\t\t\tlet tmpHistContainer = document.getElementById('DataCloner-Throughput-Histogram');\n\t\t\tif (tmpHistContainer) tmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine data source: live during sync, report after sync\n\t\tlet tmpTables = {};\n\t\tlet tmpThroughputSamples = [];\n\t\tlet tmpEventLog = [];\n\t\tlet tmpIsLive = false;\n\n\t\tif (tmpLiveStatus && (tmpLiveStatus.Phase === 'syncing' || tmpLiveStatus.Phase === 'stopping'))\n\t\t{\n\t\t\ttmpIsLive = true;\n\t\t\tif (tmpStatusData && tmpStatusData.Tables) tmpTables = tmpStatusData.Tables;\n\t\t\tif (tmpLiveStatus.ThroughputSamples) tmpThroughputSamples = tmpLiveStatus.ThroughputSamples;\n\t\t}\n\t\telse if (tmpReport && tmpReport.ReportVersion)\n\t\t{\n\t\t\t// Build tables object from report\n\t\t\tfor (let i = 0; i < tmpReport.Tables.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpT = tmpReport.Tables[i];\n\t\t\t\ttmpTables[tmpT.Name] = tmpT;\n\t\t\t}\n\t\t\ttmpThroughputSamples = tmpReport.ThroughputSamples || [];\n\t\t\ttmpEventLog = tmpReport.EventLog || [];\n\t\t}\n\t\telse if (tmpStatusData && tmpStatusData.Tables)\n\t\t{\n\t\t\ttmpTables = tmpStatusData.Tables;\n\t\t\t// Use throughput samples from live status if available (e.g. after page reload with completed sync)\n\t\t\tif (tmpLiveStatus && tmpLiveStatus.ThroughputSamples)\n\t\t\t{\n\t\t\t\ttmpThroughputSamples = tmpLiveStatus.ThroughputSamples;\n\t\t\t}\n\t\t}\n\n\t\t// Categorize tables\n\t\tlet tmpRunning = [];\n\t\tlet tmpPending = [];\n\t\tlet tmpCompleted = [];\n\t\tlet tmpErrors = [];\n\t\tlet tmpTableNames = Object.keys(tmpTables);\n\n\t\tfor (let i = 0; i < tmpTableNames.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpTableNames[i];\n\t\t\tlet tmpT = tmpTables[tmpName];\n\t\t\tif (tmpT.Status === 'Syncing')\n\t\t\t{\n\t\t\t\ttmpRunning.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Pending')\n\t\t\t{\n\t\t\t\ttmpPending.push(tmpName);\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Complete')\n\t\t\t{\n\t\t\t\ttmpCompleted.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t\telse if (tmpT.Status === 'Error' || tmpT.Status === 'Partial')\n\t\t\t{\n\t\t\t\ttmpErrors.push({ Name: tmpName, Data: tmpT });\n\t\t\t}\n\t\t}\n\n\t\tlet tmpHtml = '';\n\n\t\t// === Summary Banner (mirrors collapsed bar counters) ===\n\t\ttmpHtml += this.buildStatusSummaryHtml();\n\n\t\t// === Section 1: Running Operations ===\n\t\tif (tmpRunning.length > 0 || tmpPending.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Running</div>';\n\t\t\tfor (let i = 0; i < tmpRunning.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpOp = tmpRunning[i];\n\t\t\t\tlet tmpPct = tmpOp.Data.Total > 0 ? Math.round((tmpOp.Data.Synced / tmpOp.Data.Total) * 100) : 0;\n\t\t\t\tlet tmpSyncedFmt = this.formatNumber(tmpOp.Data.Synced || 0);\n\t\t\t\tlet tmpTotalFmt = this.formatNumber(tmpOp.Data.Total || 0);\n\t\t\t\ttmpHtml += '<div class=\"running-op-row\">';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-name\">' + this.escapeHtml(tmpOp.Name) + '</div>';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-bar\"><div class=\"running-op-bar-fill\" style=\"width:' + tmpPct + '%\"></div></div>';\n\t\t\t\ttmpHtml += ' <div class=\"running-op-count\">' + tmpSyncedFmt + ' / ' + tmpTotalFmt + ' (' + tmpPct + '%)</div>';\n\t\t\t\ttmpHtml += '</div>';\n\t\t\t}\n\t\t\tif (tmpPending.length > 0)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"running-op-pending\">' + tmpPending.length + ' table' + (tmpPending.length === 1 ? '' : 's') + ' waiting</div>';\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\t// === Section 2: Completed Successful Operations ===\n\t\tif (tmpCompleted.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Completed (' + tmpCompleted.length + ')</div>';\n\n\t\t\tfor (let i = 0; i < tmpCompleted.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += this.renderCompletedRow(tmpCompleted[i]);\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\t// === Section 3: Unsuccessful Operations ===\n\t\tif (tmpErrors.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-section\">';\n\t\t\ttmpHtml += '<div class=\"status-detail-section-title\">Errors (' + tmpErrors.length + ')</div>';\n\t\t\tfor (let i = 0; i < tmpErrors.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += this.renderErrorRow(tmpErrors[i], tmpEventLog);\n\t\t\t}\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\tif (tmpHtml === '')\n\t\t{\n\t\t\tif (tmpIsLive)\n\t\t\t{\n\t\t\t\ttmpHtml = '<div style=\"font-size:0.9em; color:#888; padding:8px 0\">Sync in progress, waiting for table data\\u2026</div>';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpHtml = '<div style=\"font-size:0.9em; color:#888; padding:8px 0\">No sync data available. Run a sync to see operation details here.</div>';\n\t\t\t}\n\t\t}\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\n\t\t// Update the throughput histogram via pict-section-histogram\n\t\tthis.updateThroughputHistogram(tmpThroughputSamples);\n\t}\n\n\tupdateThroughputHistogram(pSamples)\n\t{\n\t\tlet tmpHistContainer = document.getElementById('DataCloner-Throughput-Histogram');\n\t\tif (!tmpHistContainer) return;\n\n\t\tif (!pSamples || pSamples.length < 2)\n\t\t{\n\t\t\ttmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// --- Step 1: Compute raw deltas per 10s interval ---\n\t\tlet tmpRawDeltas = [];\n\t\tfor (let i = 1; i < pSamples.length; i++)\n\t\t{\n\t\t\tlet tmpDelta = pSamples[i].synced - pSamples[i - 1].synced;\n\t\t\tif (tmpDelta < 0) tmpDelta = 0;\n\t\t\ttmpRawDeltas.push({ delta: tmpDelta, t: pSamples[i].t });\n\t\t}\n\n\t\t// --- Step 2: Downsample if there are too many bars ---\n\t\tlet tmpContainerWidth = tmpHistContainer.clientWidth || 800;\n\t\tlet tmpMaxBars = Math.max(20, Math.floor(tmpContainerWidth / 6));\n\t\tlet tmpAggregated = tmpRawDeltas;\n\n\t\tif (tmpRawDeltas.length > tmpMaxBars)\n\t\t{\n\t\t\tlet tmpBucketSize = Math.ceil(tmpRawDeltas.length / tmpMaxBars);\n\t\t\ttmpAggregated = [];\n\t\t\tfor (let i = 0; i < tmpRawDeltas.length; i += tmpBucketSize)\n\t\t\t{\n\t\t\t\tlet tmpSum = 0;\n\t\t\t\tlet tmpLastT = 0;\n\t\t\t\tfor (let j = i; j < Math.min(i + tmpBucketSize, tmpRawDeltas.length); j++)\n\t\t\t\t{\n\t\t\t\t\ttmpSum += tmpRawDeltas[j].delta;\n\t\t\t\t\ttmpLastT = tmpRawDeltas[j].t;\n\t\t\t\t}\n\t\t\t\ttmpAggregated.push({ delta: tmpSum, t: tmpLastT });\n\t\t\t}\n\t\t}\n\n\t\t// --- Step 3: Check for data ---\n\t\tlet tmpHasData = false;\n\t\tfor (let i = 0; i < tmpAggregated.length; i++)\n\t\t{\n\t\t\tif (tmpAggregated[i].delta > 0) { tmpHasData = true; break; }\n\t\t}\n\t\tif (!tmpHasData)\n\t\t{\n\t\t\ttmpHistContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\t// --- Step 4: Build bins for the histogram library ---\n\t\tlet tmpStartT = pSamples[0].t;\n\t\tlet tmpBins = [];\n\t\tfor (let i = 0; i < tmpAggregated.length; i++)\n\t\t{\n\t\t\tlet tmpElapsedSec = Math.round((tmpAggregated[i].t - tmpStartT) / 1000);\n\t\t\ttmpBins.push({\n\t\t\t\tLabel: this.formatElapsed(tmpElapsedSec),\n\t\t\t\tValue: tmpAggregated[i].delta\n\t\t\t});\n\t\t}\n\n\t\t// --- Step 5: Update the histogram view via the library ---\n\t\ttmpHistContainer.style.display = '';\n\t\tlet tmpHistView = this.pict.views['DataCloner-StatusHistogram'];\n\t\tif (tmpHistView)\n\t\t{\n\t\t\ttmpHistView.setBins(tmpBins);\n\t\t\ttmpHistView.renderHistogram();\n\t\t}\n\t}\n\n\tbuildStatusSummaryHtml()\n\t{\n\t\tlet tmpLiveStatus = this.pict.AppData.DataCloner.LastLiveStatus;\n\t\tlet tmpReport = this.pict.AppData.DataCloner.LastReport;\n\n\t\tlet tmpParts = [];\n\t\tlet tmpMessage = '';\n\n\t\tif (tmpLiveStatus && (tmpLiveStatus.Phase === 'syncing' || tmpLiveStatus.Phase === 'stopping'))\n\t\t{\n\t\t\ttmpMessage = tmpLiveStatus.Message || '';\n\t\t\tif (tmpLiveStatus.Elapsed)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + this.escapeHtml(tmpLiveStatus.Elapsed) + '</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.ETA)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">~' + this.escapeHtml(tmpLiveStatus.ETA) + ' remaining</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.TotalTables > 0)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpLiveStatus.Completed + '</strong> / ' + tmpLiveStatus.TotalTables + ' tables</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = this.formatNumber(tmpLiveStatus.TotalSynced);\n\t\t\t\tif (tmpLiveStatus.PreCountGrandTotal > 0)\n\t\t\t\t{\n\t\t\t\t\tlet tmpGrandTotal = this.formatNumber(tmpLiveStatus.PreCountGrandTotal);\n\t\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> / ' + tmpGrandTotal + ' records</span>');\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (tmpLiveStatus.PreCountGrandTotal > 0)\n\t\t\t{\n\t\t\t\tlet tmpGrandTotal = this.formatNumber(tmpLiveStatus.PreCountGrandTotal);\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">' + tmpGrandTotal + ' records to sync</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.PreCountProgress && tmpLiveStatus.PreCountProgress.Counted < tmpLiveStatus.PreCountProgress.TotalTables)\n\t\t\t{\n\t\t\t\tlet tmpCountedSoFar = tmpLiveStatus.PreCountGrandTotal > 0\n\t\t\t\t\t? ' (' + this.formatNumber(tmpLiveStatus.PreCountGrandTotal) + ' records found)'\n\t\t\t\t\t: '';\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">counting: ' + tmpLiveStatus.PreCountProgress.Counted + ' / ' + tmpLiveStatus.PreCountProgress.TotalTables + ' tables' + tmpCountedSoFar + '</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.Errors > 0)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\" style=\"color:#dc3545\"><strong>' + tmpLiveStatus.Errors + '</strong> error' + (tmpLiveStatus.Errors === 1 ? '' : 's') + '</span>');\n\t\t\t}\n\t\t}\n\t\telse if (tmpLiveStatus && tmpLiveStatus.Phase === 'complete')\n\t\t{\n\t\t\ttmpMessage = tmpLiveStatus.Message || 'Sync complete';\n\t\t\tif (tmpLiveStatus.Elapsed)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + this.escapeHtml(tmpLiveStatus.Elapsed) + '</span>');\n\t\t\t}\n\t\t\tif (tmpLiveStatus.TotalSynced > 0)\n\t\t\t{\n\t\t\t\tlet tmpSynced = this.formatNumber(tmpLiveStatus.TotalSynced);\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpSynced + '</strong> records synced</span>');\n\t\t\t}\n\t\t}\n\t\telse if (tmpReport && tmpReport.ReportVersion)\n\t\t{\n\t\t\ttmpMessage = 'Sync ' + (tmpReport.Outcome || 'complete').toLowerCase();\n\t\t\tif (tmpReport.RunTimestamps && tmpReport.RunTimestamps.DurationSeconds)\n\t\t\t{\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\">\\u23F1 ' + this.formatElapsed(tmpReport.RunTimestamps.DurationSeconds) + '</span>');\n\t\t\t}\n\t\t\tif (tmpReport.Summary)\n\t\t\t{\n\t\t\t\tif (tmpReport.Summary.TotalSynced > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + this.formatNumber(tmpReport.Summary.TotalSynced) + '</strong> records synced</span>');\n\t\t\t\t}\n\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\"><strong>' + tmpReport.Summary.TotalTables + '</strong> tables</span>');\n\t\t\t\tif (tmpReport.Summary.TotalErrors > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpParts.push('<span class=\"live-status-meta-item\" style=\"color:#dc3545\"><strong>' + tmpReport.Summary.TotalErrors + '</strong> error' + (tmpReport.Summary.TotalErrors === 1 ? '' : 's') + '</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!tmpMessage && tmpParts.length === 0) return '';\n\n\t\tlet tmpHtml = '<div class=\"status-detail-summary\">';\n\t\tif (tmpMessage)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-summary-message\">' + this.escapeHtml(tmpMessage) + '</div>';\n\t\t}\n\t\tif (tmpParts.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"status-detail-summary-counters\">' + tmpParts.join('') + '</div>';\n\t\t}\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\tformatElapsed(pSec)\n\t{\n\t\tif (pSec < 60) return pSec + 's';\n\t\tif (pSec < 3600)\n\t\t{\n\t\t\tlet tmpM = Math.floor(pSec / 60);\n\t\t\tlet tmpS = pSec % 60;\n\t\t\treturn tmpM + ':' + (tmpS < 10 ? '0' : '') + tmpS;\n\t\t}\n\t\tlet tmpH = Math.floor(pSec / 3600);\n\t\tlet tmpM = Math.floor((pSec % 3600) / 60);\n\t\treturn tmpH + 'h' + (tmpM < 10 ? '0' : '') + tmpM;\n\t}\n\n\tformatCompact(pNum)\n\t{\n\t\tif (pNum >= 1000000) return (pNum / 1000000).toFixed(1) + 'M';\n\t\tif (pNum >= 10000) return (pNum / 1000).toFixed(0) + 'K';\n\t\tif (pNum >= 1000) return (pNum / 1000).toFixed(1) + 'K';\n\t\treturn pNum.toString();\n\t}\n\n\tformatNumber(pNum)\n\t{\n\t\treturn pNum.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t}\n\n\trenderCompletedRow(pOp)\n\t{\n\t\tlet tmpNew = pOp.Data.New || 0;\n\t\tlet tmpUpdated = pOp.Data.Updated || 0;\n\t\tlet tmpUnchanged = pOp.Data.Unchanged || 0;\n\t\tlet tmpDeleted = pOp.Data.Deleted || 0;\n\t\tlet tmpServerTotal = pOp.Data.ServerTotal || 0;\n\n\t\t// Grand total for the ratio bar: all records the adapter dealt with\n\t\tlet tmpGrandTotal = tmpUnchanged + tmpNew + tmpUpdated + tmpDeleted;\n\t\tif (tmpGrandTotal === 0 && tmpServerTotal > 0)\n\t\t{\n\t\t\ttmpGrandTotal = tmpServerTotal;\n\t\t\ttmpUnchanged = tmpServerTotal;\n\t\t}\n\n\t\tlet tmpHtml = '<div class=\"completed-op-row\">';\n\t\ttmpHtml += '<div class=\"completed-op-header\">';\n\t\ttmpHtml += ' <span class=\"completed-op-checkmark\">\\u2713</span>';\n\t\ttmpHtml += ' <span class=\"completed-op-name\">' + this.escapeHtml(pOp.Name) + '</span>';\n\t\ttmpHtml += '</div>';\n\n\t\t// Ratio bar: Unchanged / New / Updated / Deleted\n\t\tif (tmpGrandTotal > 0)\n\t\t{\n\t\t\tlet tmpUnchangedPct = Math.round((tmpUnchanged / tmpGrandTotal) * 100);\n\t\t\tlet tmpNewPct = Math.round((tmpNew / tmpGrandTotal) * 100);\n\t\t\tlet tmpUpdatedPct = Math.round((tmpUpdated / tmpGrandTotal) * 100);\n\t\t\tlet tmpDeletedPct = Math.round((tmpDeleted / tmpGrandTotal) * 100);\n\n\t\t\t// Ensure percentages sum to 100\n\t\t\tlet tmpPctSum = tmpUnchangedPct + tmpNewPct + tmpUpdatedPct + tmpDeletedPct;\n\t\t\tif (tmpPctSum !== 100 && tmpPctSum > 0)\n\t\t\t{\n\t\t\t\ttmpUnchangedPct += (100 - tmpPctSum);\n\t\t\t\tif (tmpUnchangedPct < 0) tmpUnchangedPct = 0;\n\t\t\t}\n\n\t\t\ttmpHtml += '<div class=\"ratio-bar-container\">';\n\t\t\tif (tmpUnchangedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment unchanged\" style=\"width:' + tmpUnchangedPct + '%\" title=\"Unchanged: ' + this.formatNumber(tmpUnchanged) + '\"></div>';\n\t\t\tif (tmpNewPct > 0) tmpHtml += '<div class=\"ratio-bar-segment new-records\" style=\"width:' + tmpNewPct + '%\" title=\"New: ' + this.formatNumber(tmpNew) + '\"></div>';\n\t\t\tif (tmpUpdatedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment updated\" style=\"width:' + tmpUpdatedPct + '%\" title=\"Updated: ' + this.formatNumber(tmpUpdated) + '\"></div>';\n\t\t\tif (tmpDeletedPct > 0) tmpHtml += '<div class=\"ratio-bar-segment deleted\" style=\"width:' + tmpDeletedPct + '%\" title=\"Deleted: ' + this.formatNumber(tmpDeleted) + '\"></div>';\n\t\t\ttmpHtml += '</div>';\n\n\t\t\ttmpHtml += '<div class=\"ratio-bar-legend\">';\n\t\t\tif (tmpUnchanged > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot unchanged-dot\"></span> Unchanged (' + this.formatNumber(tmpUnchanged) + ')</span>';\n\t\t\tif (tmpNew > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot new-dot\"></span> New (' + this.formatNumber(tmpNew) + ')</span>';\n\t\t\tif (tmpUpdated > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot updated-dot\"></span> Updated (' + this.formatNumber(tmpUpdated) + ')</span>';\n\t\t\tif (tmpDeleted > 0) tmpHtml += '<span class=\"ratio-bar-legend-item\"><span class=\"ratio-bar-legend-dot deleted-dot\"></span> Deleted (' + this.formatNumber(tmpDeleted) + ')</span>';\n\t\t\ttmpHtml += '</div>';\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\trenderErrorRow(pOp, pEventLog)\n\t{\n\t\tlet tmpSynced = pOp.Data.Synced || 0;\n\t\tlet tmpTotal = pOp.Data.Total || 0;\n\t\tlet tmpSyncedFmt = this.formatNumber(tmpSynced);\n\t\tlet tmpTotalFmt = this.formatNumber(tmpTotal);\n\n\t\tlet tmpHtml = '<div class=\"error-op-row\">';\n\t\ttmpHtml += '<div class=\"error-op-header\">';\n\t\ttmpHtml += ' <span style=\"color:#dc3545\">\\u2717</span>';\n\t\ttmpHtml += ' <span class=\"error-op-name\">' + this.escapeHtml(pOp.Name) + '</span>';\n\t\ttmpHtml += ' <span class=\"error-op-status\">' + pOp.Data.Status + ' \\u2014 ' + tmpSyncedFmt + ' / ' + tmpTotalFmt + '</span>';\n\t\ttmpHtml += '</div>';\n\n\t\tif (pOp.Data.ErrorMessage)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"error-op-message\">' + this.escapeHtml(pOp.Data.ErrorMessage) + '</div>';\n\t\t}\n\n\t\t// Extract relevant log entries from EventLog\n\t\tif (pEventLog && pEventLog.length > 0)\n\t\t{\n\t\t\tlet tmpRelevantLogs = [];\n\t\t\tfor (let j = 0; j < pEventLog.length; j++)\n\t\t\t{\n\t\t\t\tlet tmpLog = pEventLog[j];\n\t\t\t\tif (tmpLog.Data && tmpLog.Data.Table === pOp.Name &&\n\t\t\t\t\t(tmpLog.Type === 'TableError' || tmpLog.Type === 'TablePartial'))\n\t\t\t\t{\n\t\t\t\t\ttmpRelevantLogs.push(tmpLog);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tmpRelevantLogs.length > 0)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"error-op-log-entries\">';\n\t\t\t\tfor (let j = 0; j < tmpRelevantLogs.length; j++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpTimestamp = tmpRelevantLogs[j].Timestamp.replace('T', ' ').replace(/\\.\\d+Z$/, '');\n\t\t\t\t\ttmpHtml += '<div>' + this.escapeHtml(tmpTimestamp + ' ' + tmpRelevantLogs[j].Message) + '</div>';\n\t\t\t\t}\n\t\t\t\ttmpHtml += '</div>';\n\t\t\t}\n\t\t}\n\n\t\ttmpHtml += '</div>';\n\t\treturn tmpHtml;\n\t}\n\n\t// ================================================================\n\t// Deployed Tables Persistence\n\t// ================================================================\n\n\tsaveDeployedTables()\n\t{\n\t\tlocalStorage.setItem('dataCloner_deployedTables', JSON.stringify(this.pict.AppData.DataCloner.DeployedTables));\n\t}\n\n\trestoreDeployedTables()\n\t{\n\t\ttry\n\t\t{\n\t\t\tlet tmpRaw = localStorage.getItem('dataCloner_deployedTables');\n\t\t\tif (tmpRaw)\n\t\t\t{\n\t\t\t\tthis.pict.AppData.DataCloner.DeployedTables = JSON.parse(tmpRaw);\n\t\t\t\tthis.pict.views['DataCloner-ViewData'].populateViewTableDropdown();\n\t\t\t}\n\t\t}\n\t\tcatch (pError) { /* ignore */ }\n\t}\n\n\t// ================================================================\n\t// Auto-Process\n\t// ================================================================\n\n\tinitAutoProcess()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.api('GET', '/clone/sync/live-status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Phase === 'syncing' || pData.Phase === 'stopping')\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.ServerBusyAtLoad = true;\n\t\t\t\t\ttmpSelf.setSectionPhase(5, 'busy');\n\t\t\t\t\ttmpSelf.pict.views['DataCloner-Sync'].startPolling();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttmpSelf.runAutoProcessChain();\n\t\t\t})\n\t\t\t.catch(function()\n\t\t\t{\n\t\t\t\t// Server unreachable — don't auto-process\n\t\t\t});\n\t}\n\n\trunAutoProcessChain()\n\t{\n\t\tlet tmpSelf = this;\n\t\tlet tmpDelay = 0;\n\t\tlet tmpStepDelay = 2000;\n\n\t\tif (document.getElementById('auto1') && document.getElementById('auto1').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Connection'].connectProvider(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto2') && document.getElementById('auto2').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Session'].goAction(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay + 1500;\n\t\t}\n\t\tif (document.getElementById('auto3') && document.getElementById('auto3').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Schema'].fetchSchema(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto4') && document.getElementById('auto4').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Deploy'].deploySchema(); }, tmpDelay);\n\t\t\ttmpDelay += tmpStepDelay;\n\t\t}\n\t\tif (document.getElementById('auto5') && document.getElementById('auto5').checked)\n\t\t{\n\t\t\tsetTimeout(function() { tmpSelf.pict.views['DataCloner-Sync'].startSync(); }, tmpDelay);\n\t\t}\n\t}\n}\n\nmodule.exports = DataClonerProvider;\n\nmodule.exports.default_configuration =\n{\n\tProviderIdentifier: 'DataCloner',\n\tAutoInitialize: true,\n\tAutoInitializeOrdinal: 0\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerConnectionView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tonProviderChange()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpProviders = ['SQLite', 'MySQL', 'MSSQL', 'PostgreSQL', 'Solr', 'MongoDB', 'RocksDB', 'Bibliograph'];\n\t\tfor (let i = 0; i < tmpProviders.length; i++)\n\t\t{\n\t\t\tlet tmpEl = document.getElementById('config' + tmpProviders[i]);\n\t\t\tif (tmpEl)\n\t\t\t{\n\t\t\t\ttmpEl.style.display = (tmpProvider === tmpProviders[i]) ? '' : 'none';\n\t\t\t}\n\t\t}\n\t\tthis.pict.providers.DataCloner.saveField('connProvider');\n\t}\n\n\tgetProviderConfig()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\ttmpConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || '~/headlight-liveconnect-local/cloned.sqlite';\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpConfig.password = document.getElementById('mysqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mysqlDatabase').value.trim();\n\t\t\ttmpConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpConfig.password = document.getElementById('mssqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mssqlDatabase').value.trim();\n\t\t\ttmpConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;\n\t\t\ttmpConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';\n\t\t\ttmpConfig.password = document.getElementById('postgresqlPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('postgresqlDatabase').value.trim();\n\t\t\ttmpConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;\n\t\t}\n\t\telse if (tmpProvider === 'Solr')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('solrHost').value.trim() || 'localhost';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('solrPort').value, 10) || 8983;\n\t\t\ttmpConfig.core = document.getElementById('solrCore').value.trim() || 'default';\n\t\t\ttmpConfig.path = document.getElementById('solrPath').value.trim() || '/solr';\n\t\t\ttmpConfig.secure = document.getElementById('solrSecure').checked;\n\t\t}\n\t\telse if (tmpProvider === 'MongoDB')\n\t\t{\n\t\t\ttmpConfig.host = document.getElementById('mongodbHost').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.port = parseInt(document.getElementById('mongodbPort').value, 10) || 27017;\n\t\t\ttmpConfig.user = document.getElementById('mongodbUser').value.trim();\n\t\t\ttmpConfig.password = document.getElementById('mongodbPassword').value;\n\t\t\ttmpConfig.database = document.getElementById('mongodbDatabase').value.trim() || 'test';\n\t\t\ttmpConfig.maxPoolSize = parseInt(document.getElementById('mongodbConnectionLimit').value, 10) || 10;\n\t\t}\n\t\telse if (tmpProvider === 'RocksDB')\n\t\t{\n\t\t\ttmpConfig.RocksDBFolder = document.getElementById('rocksdbFolder').value.trim() || 'data/rocksdb';\n\t\t}\n\t\telse if (tmpProvider === 'Bibliograph')\n\t\t{\n\t\t\ttmpConfig.StorageFolder = document.getElementById('bibliographFolder').value.trim() || 'data/bibliograph';\n\t\t}\n\n\t\treturn { Provider: tmpProvider, Config: tmpConfig };\n\t}\n\n\tconnectProvider()\n\t{\n\t\t// Guard against re-entrant calls (e.g. rapid auto-connect polling)\n\t\tif (this._connectInFlight)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tthis._connectInFlight = true;\n\n\t\tlet tmpConnInfo = this.getProviderConfig();\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connecting to ' + tmpConnInfo.Provider + '...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/connection/configure', tmpConnInfo)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\ttmpSelf._connectInFlight = false;\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');\n\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(1, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('connectionStatus', 'Connection failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(1, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\ttmpSelf._connectInFlight = false;\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(1, 'error');\n\t\t\t\t});\n\t}\n\n\ttestConnection()\n\t{\n\t\tlet tmpConnInfo = this.getProviderConfig();\n\n\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Testing ' + tmpConnInfo.Provider + ' connection...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/connection/test', tmpConnInfo)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Test failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tcheckConnectionStatus()\n\t{\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/connection/status')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Connected)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('connectionStatus', 'Connected: ' + pData.Provider, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(1, 'ok');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t() =>\n\t\t\t\t{\n\t\t\t\t\t/* ignore */\n\t\t\t\t});\n\t}\n}\n\nmodule.exports = DataClonerConnectionView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Connection',\n\tDefaultRenderable: 'DataCloner-Connection',\n\tDefaultDestinationAddress: '#DataCloner-Section-Connection',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Connection',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">1</div>\n\t<div class=\"accordion-card\" id=\"section1\" data-section=\"1\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section1')\">\n\t\t\t<div class=\"accordion-title\">Database Connection</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase1\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview1\">SQLite at data/cloned.sqlite</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Connection'].connectProvider()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto1\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Configure the local database where cloned data will be stored. SQLite is connected by default.</p>\n\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:0 0 200px\">\n\t\t\t\t\t<label for=\"connProvider\">Provider</label>\n\t\t\t\t\t<select id=\"connProvider\" onchange=\"pict.views['DataCloner-Connection'].onProviderChange()\">\n\t\t\t\t\t\t<option value=\"SQLite\" selected>SQLite</option>\n\t\t\t\t\t\t<option value=\"MySQL\">MySQL</option>\n\t\t\t\t\t\t<option value=\"MSSQL\">MSSQL</option>\n\t\t\t\t\t\t<option value=\"PostgreSQL\">PostgreSQL</option>\n\t\t\t\t\t\t<option value=\"Solr\">Solr</option>\n\t\t\t\t\t\t<option value=\"MongoDB\">MongoDB</option>\n\t\t\t\t\t\t<option value=\"RocksDB\">RocksDB</option>\n\t\t\t\t\t\t<option value=\"Bibliograph\">Bibliograph</option>\n\t\t\t\t\t</select>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:1; display:flex; align-items:flex-end; gap:8px\">\n\t\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Connection'].connectProvider()\">Connect</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Connection'].testConnection()\">Test Connection</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- SQLite Config -->\n\t\t\t<div id=\"configSQLite\">\n\t\t\t\t<label for=\"sqliteFilePath\">SQLite File Path</label>\n\t\t\t\t<input type=\"text\" id=\"sqliteFilePath\" placeholder=\"~/headlight-liveconnect-local/cloned.sqlite\" value=\"~/headlight-liveconnect-local/cloned.sqlite\">\n\t\t\t</div>\n\n\t\t\t<!-- MySQL Config -->\n\t\t\t<div id=\"configMySQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mysqlServer\">Server</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mysqlServer\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mysqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mysqlPort\" placeholder=\"3306\" value=\"3306\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mysqlUser\" placeholder=\"root\" value=\"root\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mysqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mysqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mysqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mysqlConnectionLimit\">Connection Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mysqlConnectionLimit\" placeholder=\"20\" value=\"20\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- MSSQL Config -->\n\t\t\t<div id=\"configMSSQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mssqlServer\">Server</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mssqlServer\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mssqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mssqlPort\" placeholder=\"1433\" value=\"1433\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mssqlUser\" placeholder=\"sa\" value=\"sa\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mssqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mssqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mssqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mssqlConnectionLimit\">Connection Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mssqlConnectionLimit\" placeholder=\"20\" value=\"20\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- PostgreSQL Config -->\n\t\t\t<div id=\"configPostgreSQL\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"postgresqlHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"postgresqlHost\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"postgresqlPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"postgresqlPort\" placeholder=\"5432\" value=\"5432\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"postgresqlUser\" placeholder=\"postgres\" value=\"postgres\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"postgresqlPassword\" placeholder=\"password\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"postgresqlDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"postgresqlDatabase\" placeholder=\"meadow_clone\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"postgresqlConnectionLimit\">Connection Pool Limit</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"postgresqlConnectionLimit\" placeholder=\"10\" value=\"10\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- Solr Config -->\n\t\t\t<div id=\"configSolr\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"solrHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrHost\" placeholder=\"localhost\" value=\"localhost\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"solrPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"solrPort\" placeholder=\"8983\" value=\"8983\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"solrCore\">Core</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrCore\" placeholder=\"default\" value=\"default\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"solrPath\">Path</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"solrPath\" placeholder=\"/solr\" value=\"/solr\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t\t<input type=\"checkbox\" id=\"solrSecure\">\n\t\t\t\t\t<label for=\"solrSecure\">Use HTTPS</label>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- MongoDB Config -->\n\t\t\t<div id=\"configMongoDB\" style=\"display:none\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t\t<label for=\"mongodbHost\">Host</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mongodbHost\" placeholder=\"127.0.0.1\" value=\"127.0.0.1\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t\t<label for=\"mongodbPort\">Port</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mongodbPort\" placeholder=\"27017\" value=\"27017\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbUser\">User</label>\n\t\t\t\t\t\t<input type=\"text\" id=\"mongodbUser\" placeholder=\"(optional)\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbPassword\">Password</label>\n\t\t\t\t\t\t<input type=\"password\" id=\"mongodbPassword\" placeholder=\"(optional)\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<label for=\"mongodbDatabase\">Database</label>\n\t\t\t\t<input type=\"text\" id=\"mongodbDatabase\" placeholder=\"test\" value=\"test\">\n\t\t\t\t<div class=\"inline-group\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label for=\"mongodbConnectionLimit\">Max Pool Size</label>\n\t\t\t\t\t\t<input type=\"number\" id=\"mongodbConnectionLimit\" placeholder=\"10\" value=\"10\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- RocksDB Config -->\n\t\t\t<div id=\"configRocksDB\" style=\"display:none\">\n\t\t\t\t<label for=\"rocksdbFolder\">RocksDB Folder Path</label>\n\t\t\t\t<input type=\"text\" id=\"rocksdbFolder\" placeholder=\"data/rocksdb\" value=\"data/rocksdb\">\n\t\t\t</div>\n\n\t\t\t<!-- Bibliograph Config -->\n\t\t\t<div id=\"configBibliograph\" style=\"display:none\">\n\t\t\t\t<label for=\"bibliographFolder\">Storage Folder Path</label>\n\t\t\t\t<input type=\"text\" id=\"bibliographFolder\" placeholder=\"data/bibliograph\" value=\"data/bibliograph\">\n\t\t\t</div>\n\n\t\t\t<div id=\"connectionStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Connection',\n\t\t\tTemplateHash: 'DataCloner-Connection',\n\t\t\tDestinationAddress: '#DataCloner-Section-Connection'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerDeployView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tdeploySchema()\n\t{\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\n\t\tif (tmpSelectedTables.length === 0)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'No tables selected. Fetch a schema and select tables first.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(4, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'Deploying ' + tmpSelectedTables.length + ' tables...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/deploy', { Tables: tmpSelectedTables })\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\tlet tmpStatusMsg = pData.Message;\n\n\t\t\t\t\t// Append migration details if schema deltas were applied\n\t\t\t\t\tif (Array.isArray(pData.MigrationsApplied) && pData.MigrationsApplied.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tlet tmpDetails = pData.MigrationsApplied.map(function(pM)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn pM.Table + ': +' + pM.ColumnsAdded.join(', +');\n\t\t\t\t\t\t});\n\t\t\t\t\t\ttmpStatusMsg += '\\nMigrations: ' + tmpDetails.join('; ');\n\t\t\t\t\t}\n\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', tmpStatusMsg, 'ok');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'ok');\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.DeployedTables = pData.TablesDeployed || tmpSelectedTables;\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.saveDeployedTables();\n\t\t\t\t\ttmpSelf.pict.views['DataCloner-ViewData'].populateViewTableDropdown();\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.updateAllPreviews();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Deploy failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');\n\t\t\t});\n\t}\n\n\tauditGUIDIndices()\n\t{\n\t\tlet tmpReportEl = document.getElementById('guidIndexReport');\n\t\tif (tmpReportEl) tmpReportEl.innerHTML = '<span style=\"color:#888\">Checking GUID indices...</span>';\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/schema/guid-index-audit')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (!tmpReportEl) return;\n\n\t\t\t\tif (!pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpReportEl.innerHTML = '<span style=\"color:red\">' + (pData.Error || 'Audit failed') + '</span>';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (pData.MissingCount === 0)\n\t\t\t\t{\n\t\t\t\t\ttmpReportEl.innerHTML = '<span style=\"color:green\">All GUID columns have indices.</span>';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet tmpHTML = '<div style=\"margin-top:6px\"><strong>' + pData.Message + '</strong></div>';\n\t\t\t\ttmpHTML += '<table style=\"font-size:0.85em; margin:6px 0; border-collapse:collapse; width:100%\">';\n\t\t\t\ttmpHTML += '<tr style=\"text-align:left; border-bottom:1px solid #ccc\"><th style=\"padding:3px 8px\">Table</th><th style=\"padding:3px 8px\">GUID Column</th><th style=\"padding:3px 8px\">Index</th></tr>';\n\n\t\t\t\tfor (let t = 0; t < pData.Tables.length; t++)\n\t\t\t\t{\n\t\t\t\t\tlet tmpTable = pData.Tables[t];\n\t\t\t\t\tfor (let c = 0; c < tmpTable.GUIDColumns.length; c++)\n\t\t\t\t\t{\n\t\t\t\t\t\tlet tmpCol = tmpTable.GUIDColumns[c];\n\t\t\t\t\t\tlet tmpStatus = tmpCol.HasIndex\n\t\t\t\t\t\t\t? '<span style=\"color:green\">' + tmpCol.IndexName + '</span>'\n\t\t\t\t\t\t\t: '<span style=\"color:red\">MISSING</span>';\n\t\t\t\t\t\ttmpHTML += '<tr style=\"border-bottom:1px solid #eee\"><td style=\"padding:3px 8px\">' + tmpTable.Table + '</td><td style=\"padding:3px 8px\">' + tmpCol.Column + '</td><td style=\"padding:3px 8px\">' + tmpStatus + '</td></tr>';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttmpHTML += '</table>';\n\t\t\t\ttmpHTML += '<button class=\"primary\" style=\"margin-top:4px\" onclick=\"pict.views[\\'DataCloner-Deploy\\'].createMissingGUIDIndices()\">Create Missing Indices</button>';\n\n\t\t\t\ttmpReportEl.innerHTML = tmpHTML;\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\tif (tmpReportEl) tmpReportEl.innerHTML = '<span style=\"color:red\">Request failed: ' + pError.message + '</span>';\n\t\t\t});\n\t}\n\n\tcreateMissingGUIDIndices()\n\t{\n\t\tlet tmpReportEl = document.getElementById('guidIndexReport');\n\t\tif (tmpReportEl) tmpReportEl.innerHTML = '<span style=\"color:#888\">Creating GUID indices...</span>';\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/guid-index-create')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (!tmpReportEl) return;\n\n\t\t\t\tif (!pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpReportEl.innerHTML = '<span style=\"color:red\">' + (pData.Error || 'Index creation failed') + '</span>';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet tmpHTML = '<div style=\"margin-top:6px; color:green\"><strong>' + pData.Message + '</strong></div>';\n\n\t\t\t\tif (pData.IndicesCreated && pData.IndicesCreated.length > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpHTML += '<ul style=\"font-size:0.85em; margin:4px 0\">';\n\t\t\t\t\tfor (let i = 0; i < pData.IndicesCreated.length; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tlet tmpIdx = pData.IndicesCreated[i];\n\t\t\t\t\t\ttmpHTML += '<li>' + tmpIdx.Table + ': ' + tmpIdx.IndexName + '</li>';\n\t\t\t\t\t}\n\t\t\t\t\ttmpHTML += '</ul>';\n\t\t\t\t}\n\n\t\t\t\ttmpHTML += '<button style=\"margin-top:4px\" onclick=\"pict.views[\\'DataCloner-Deploy\\'].auditGUIDIndices()\">Re-check</button>';\n\t\t\t\ttmpReportEl.innerHTML = tmpHTML;\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\tif (tmpReportEl) tmpReportEl.innerHTML = '<span style=\"color:red\">Request failed: ' + pError.message + '</span>';\n\t\t\t});\n\t}\n\n\tresetDatabase()\n\t{\n\t\tif (!confirm('This will delete ALL data in the local SQLite database. Continue?'))\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('deployStatus', 'Resetting database...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/reset')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', pData.Message, 'ok');\n\t\t\t\t\t// Clear the sync progress display\n\t\t\t\t\tlet tmpSyncProgress = document.getElementById('syncProgress');\n\t\t\t\t\tif (tmpSyncProgress) tmpSyncProgress.innerHTML = '';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Reset failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n}\n\nmodule.exports = DataClonerDeployView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Deploy',\n\tDefaultRenderable: 'DataCloner-Deploy',\n\tDefaultDestinationAddress: '#DataCloner-Section-Deploy',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Deploy',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">4</div>\n\t<div class=\"accordion-card\" id=\"section4\" data-section=\"4\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section4')\">\n\t\t\t<div class=\"accordion-title\">Deploy Schema</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase4\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview4\">Create selected tables in the local database</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Deploy'].deploySchema()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto4\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Creates the selected tables in the local database and sets up CRUD endpoints (e.g. GET /1.0/Documents).</p>\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Deploy'].deploySchema()\">Deploy Selected Tables</button>\n\t\t\t<button onclick=\"pict.views['DataCloner-Deploy'].auditGUIDIndices()\">Check GUID Indices</button>\n\t\t\t<button class=\"danger\" onclick=\"pict.views['DataCloner-Deploy'].resetDatabase()\">Reset Database</button>\n\t\t\t<div id=\"deployStatus\"></div>\n\t\t\t<div id=\"guidIndexReport\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Deploy',\n\t\t\tTemplateHash: 'DataCloner-Deploy',\n\t\t\tDestinationAddress: '#DataCloner-Section-Deploy'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerExportView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tbuildConfigObject()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\t// ---- Local Database ----\n\t\ttmpConfig.LocalDatabase = { Provider: tmpProvider, Config: {} };\n\t\tlet tmpDbConfig = tmpConfig.LocalDatabase.Config;\n\n\t\tif (tmpProvider === 'SQLite')\n\t\t{\n\t\t\ttmpDbConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || '~/headlight-liveconnect-local/cloned.sqlite';\n\t\t}\n\t\telse if (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpDbConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpDbConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpDbConfig.password = document.getElementById('mysqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('mysqlDatabase').value.trim();\n\t\t\ttmpDbConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpDbConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpDbConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpDbConfig.password = document.getElementById('mssqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('mssqlDatabase').value.trim();\n\t\t\ttmpDbConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'PostgreSQL')\n\t\t{\n\t\t\ttmpDbConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';\n\t\t\ttmpDbConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;\n\t\t\ttmpDbConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';\n\t\t\ttmpDbConfig.password = document.getElementById('postgresqlPassword').value;\n\t\t\ttmpDbConfig.database = document.getElementById('postgresqlDatabase').value.trim();\n\t\t\ttmpDbConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;\n\t\t}\n\n\t\t// ---- Remote Session ----\n\t\ttmpConfig.RemoteSession = {};\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\tif (tmpServerURL) tmpConfig.RemoteSession.ServerURL = tmpServerURL + '/1.0/';\n\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim();\n\t\tif (tmpAuthMethod) tmpConfig.RemoteSession.AuthenticationMethod = tmpAuthMethod;\n\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI) tmpConfig.RemoteSession.AuthenticationURITemplate = tmpAuthURI;\n\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI) tmpConfig.RemoteSession.CheckSessionURITemplate = tmpCheckURI;\n\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\tif (tmpCookieName) tmpConfig.RemoteSession.CookieName = tmpCookieName;\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr) tmpConfig.RemoteSession.CookieValueAddress = tmpCookieValueAddr;\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate) tmpConfig.RemoteSession.CookieValueTemplate = tmpCookieValueTemplate;\n\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\tif (tmpLoginMarker) tmpConfig.RemoteSession.CheckSessionLoginMarker = tmpLoginMarker;\n\n\t\t// ---- Credentials ----\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value;\n\t\tif (tmpUserName || tmpPassword)\n\t\t{\n\t\t\ttmpConfig.Credentials = {};\n\t\t\tif (tmpUserName) tmpConfig.Credentials.UserName = tmpUserName;\n\t\t\tif (tmpPassword) tmpConfig.Credentials.Password = tmpPassword;\n\t\t}\n\n\t\t// ---- Schema ----\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tif (tmpSchemaURL) tmpConfig.SchemaURL = tmpSchemaURL;\n\n\t\t// ---- Tables ----\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\tif (tmpSelectedTables.length > 0) tmpConfig.Tables = tmpSelectedTables;\n\n\t\t// ---- Sync Options ----\n\t\ttmpConfig.Sync = {};\n\t\ttmpConfig.Sync.Mode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\ttmpConfig.Sync.PageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\ttmpConfig.Sync.SyncDeletedRecords = document.getElementById('syncDeletedRecords').checked;\n\t\tlet tmpPrecision = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (!isNaN(tmpPrecision) && tmpPrecision !== 1000) tmpConfig.Sync.DateTimePrecisionMS = tmpPrecision;\n\t\tlet tmpMaxRecords = parseInt(document.getElementById('syncMaxRecords').value, 10);\n\t\tif (tmpMaxRecords > 0) tmpConfig.Sync.MaxRecords = tmpMaxRecords;\n\t\tif (document.getElementById('syncAdvancedIDPagination').checked) tmpConfig.Sync.UseAdvancedIDPagination = true;\n\n\t\treturn tmpConfig;\n\t}\n\n\tbuildMeadowIntegrationConfig()\n\t{\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tlet tmpConfig = {};\n\n\t\t// ---- Source ----\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\ttmpConfig.Source = { ServerURL: tmpServerURL ? tmpServerURL + '/1.0/' : 'https://localhost:8080/1.0/' };\n\t\t// When SessionManager handles auth, Source credentials are not needed\n\t\ttmpConfig.Source.UserID = false;\n\t\ttmpConfig.Source.Password = false;\n\n\t\t// ---- Destination ----\n\t\t// meadow-integration clone supports MySQL and MSSQL\n\t\ttmpConfig.Destination = {};\n\t\tif (tmpProvider === 'MySQL')\n\t\t{\n\t\t\ttmpConfig.Destination.Provider = 'MySQL';\n\t\t\ttmpConfig.Destination.MySQL = {};\n\t\t\ttmpConfig.Destination.MySQL.server = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.Destination.MySQL.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;\n\t\t\ttmpConfig.Destination.MySQL.user = document.getElementById('mysqlUser').value.trim() || 'root';\n\t\t\ttmpConfig.Destination.MySQL.password = document.getElementById('mysqlPassword').value || '';\n\t\t\ttmpConfig.Destination.MySQL.database = document.getElementById('mysqlDatabase').value.trim() || 'meadow';\n\t\t\ttmpConfig.Destination.MySQL.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse if (tmpProvider === 'MSSQL')\n\t\t{\n\t\t\ttmpConfig.Destination.Provider = 'MSSQL';\n\t\t\ttmpConfig.Destination.MSSQL = {};\n\t\t\ttmpConfig.Destination.MSSQL.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';\n\t\t\ttmpConfig.Destination.MSSQL.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;\n\t\t\ttmpConfig.Destination.MSSQL.user = document.getElementById('mssqlUser').value.trim() || 'sa';\n\t\t\ttmpConfig.Destination.MSSQL.password = document.getElementById('mssqlPassword').value || '';\n\t\t\ttmpConfig.Destination.MSSQL.database = document.getElementById('mssqlDatabase').value.trim() || 'meadow';\n\t\t\ttmpConfig.Destination.MSSQL.ConnectionPoolLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Default to MySQL placeholder for unsupported providers\n\t\t\ttmpConfig.Destination.Provider = 'MySQL';\n\t\t\ttmpConfig.Destination.MySQL = { server: '127.0.0.1', port: 3306, user: 'root', password: '', database: 'meadow', connectionLimit: 20 };\n\t\t}\n\n\t\t// ---- Schema ----\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tif (tmpSchemaURL)\n\t\t{\n\t\t\ttmpConfig.SchemaURL = tmpSchemaURL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpConfig.SchemaPath = './schema/Model-Extended.json';\n\t\t}\n\n\t\t// ---- Sync ----\n\t\ttmpConfig.Sync = {};\n\t\ttmpConfig.Sync.DefaultSyncMode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\ttmpConfig.Sync.PageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\tlet tmpMdwintPrecision = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (!isNaN(tmpMdwintPrecision)) tmpConfig.Sync.DateTimePrecisionMS = tmpMdwintPrecision;\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\ttmpConfig.Sync.SyncEntityList = tmpSelectedTables.length > 0 ? tmpSelectedTables : [];\n\t\ttmpConfig.Sync.SyncEntityOptions = {};\n\t\tif (document.getElementById('syncAdvancedIDPagination').checked) tmpConfig.Sync.UseAdvancedIDPagination = true;\n\n\t\t// ---- SessionManager ----\n\t\ttmpConfig.SessionManager = { Sessions: {} };\n\n\t\tlet tmpSessionConfig = {};\n\t\ttmpSessionConfig.Type = 'Cookie';\n\n\t\t// Authentication method\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim() || 'get';\n\t\ttmpSessionConfig.AuthenticationMethod = tmpAuthMethod;\n\n\t\t// Build the authentication URI template\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI)\n\t\t{\n\t\t\t// If the URI is a relative path, prepend the server URL\n\t\t\tif (tmpAuthURI.charAt(0) === '/')\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = (tmpServerURL || '') + tmpAuthURI;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpAuthURI;\n\t\t\t}\n\t\t}\n\t\telse if (tmpServerURL)\n\t\t{\n\t\t\t// Default: Meadow-style GET authentication\n\t\t\tif (tmpAuthMethod === 'post')\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpServerURL + '/1.0/Authenticate';\n\t\t\t\ttmpSessionConfig.AuthenticationRequestBody = {\n\t\t\t\t\tUserName: '{~D:Record.UserName~}',\n\t\t\t\t\tPassword: '{~D:Record.Password~}'\n\t\t\t\t};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpSessionConfig.AuthenticationURITemplate = tmpServerURL + '/1.0/Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}';\n\t\t\t}\n\t\t}\n\n\t\t// Check session URI\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI)\n\t\t{\n\t\t\ttmpSessionConfig.CheckSessionURITemplate = tmpCheckURI.charAt(0) === '/' ? (tmpServerURL || '') + tmpCheckURI : tmpCheckURI;\n\t\t}\n\t\telse if (tmpServerURL)\n\t\t{\n\t\t\ttmpSessionConfig.CheckSessionURITemplate = tmpServerURL + '/1.0/CheckSession';\n\t\t}\n\n\t\t// Login marker\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\ttmpSessionConfig.CheckSessionLoginMarkerType = 'boolean';\n\t\ttmpSessionConfig.CheckSessionLoginMarker = tmpLoginMarker || 'LoggedIn';\n\n\t\t// Domain match — extract from server URL for auto-injection\n\t\tif (tmpServerURL)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tlet tmpUrlObj = new URL(tmpServerURL);\n\t\t\t\ttmpSessionConfig.DomainMatch = tmpUrlObj.host;\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\ttmpSessionConfig.DomainMatch = tmpServerURL;\n\t\t\t}\n\t\t}\n\n\t\t// Cookie injection\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\ttmpSessionConfig.CookieName = tmpCookieName || 'SessionID';\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr) tmpSessionConfig.CookieValueAddress = tmpCookieValueAddr;\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate) tmpSessionConfig.CookieValueTemplate = tmpCookieValueTemplate;\n\n\t\t// Credentials\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value;\n\t\ttmpSessionConfig.Credentials = {};\n\t\tif (tmpUserName) tmpSessionConfig.Credentials.UserName = tmpUserName;\n\t\tif (tmpPassword) tmpSessionConfig.Credentials.Password = tmpPassword;\n\n\t\ttmpConfig.SessionManager.Sessions.SourceAPI = tmpSessionConfig;\n\n\t\treturn tmpConfig;\n\t}\n\n\tgenerateConfig()\n\t{\n\t\tlet tmpConfig = this.buildConfigObject();\n\t\tlet tmpJson = JSON.stringify(tmpConfig, null, '\\t');\n\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\ttmpTextarea.value = tmpJson;\n\t\ttmpTextarea.style.display = '';\n\n\t\t// Build CLI flags from export options\n\t\tlet tmpLogFlag = document.getElementById('syncLogFile').checked ? ' --log' : '';\n\t\tlet tmpMaxFlag = '';\n\t\tlet tmpExportMax = parseInt(document.getElementById('syncMaxRecords').value, 10);\n\t\tif (tmpExportMax > 0) tmpMaxFlag = ' --max ' + tmpExportMax;\n\n\t\t// Build CLI command (with config file)\n\t\tlet tmpCliDiv = document.getElementById('cliCommand');\n\t\ttmpCliDiv.style.display = '';\n\t\ttmpCliDiv.querySelector('div').textContent = 'npx retold-data-service-clone --config clone-config.json --run' + tmpLogFlag + tmpMaxFlag;\n\n\t\t// Build one-liner (no config file needed) using --config-json\n\t\tlet tmpOneShotDiv = document.getElementById('cliOneShot');\n\t\ttmpOneShotDiv.style.display = '';\n\t\tlet tmpCompactJSON = JSON.stringify(tmpConfig);\n\t\t// Escape single quotes for shell wrapping\n\t\tlet tmpEscapedJSON = tmpCompactJSON.replace(/'/g, \"'\\\\''\");\n\t\tlet tmpOneShot = \"npx retold-data-service-clone --config-json '\" + tmpEscapedJSON + \"' --run\" + tmpLogFlag + tmpMaxFlag;\n\t\ttmpOneShotDiv.querySelector('div').textContent = tmpOneShot;\n\n\t\t// ---- meadow-integration (mdwint clone) config ----\n\t\tlet tmpMdwintConfig = this.buildMeadowIntegrationConfig();\n\t\tlet tmpMdwintJSON = JSON.stringify(tmpMdwintConfig, null, '\\t');\n\n\t\tlet tmpMdwintDiv = document.getElementById('mdwintExport');\n\t\ttmpMdwintDiv.style.display = '';\n\n\t\tlet tmpMdwintTextarea = document.getElementById('mdwintConfigOutput');\n\t\ttmpMdwintTextarea.value = tmpMdwintJSON;\n\n\t\t// Build the mdwint CLI command\n\t\tlet tmpMdwintCLI = 'mdwint clone --schema_path ./schema/Model-Extended.json';\n\t\tlet tmpMdwintCLIDiv = document.getElementById('mdwintCLICommand');\n\t\ttmpMdwintCLIDiv.querySelector('div').textContent = tmpMdwintCLI;\n\n\t\t// Provider compatibility note\n\t\tlet tmpProvider = document.getElementById('connProvider').value;\n\t\tif (tmpProvider !== 'MySQL' && tmpProvider !== 'MSSQL')\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Note: mdwint clone only supports MySQL and MSSQL destinations. The config defaults to MySQL; update the Destination section for your target database.', 'warn');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', '', '');\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Config generated. Save as clone-config.json or copy the one-liner below.', 'ok');\n\t}\n\n\tcopyConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Generate a config first.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpTextarea.value).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'Config copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyCLI()\n\t{\n\t\tlet tmpCmd = document.getElementById('cliCommand').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'CLI command copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyOneShot()\n\t{\n\t\tlet tmpCmd = document.getElementById('cliOneShot').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('configExportStatus', 'One-liner copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tdownloadConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('configOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.generateConfig();\n\t\t}\n\t\tlet tmpBlob = new Blob([tmpTextarea.value], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\ttmpAnchor.download = 'clone-config.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('configExportStatus', 'Config downloaded as clone-config.json.', 'ok');\n\t}\n\n\tcopyMdwintConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('mdwintConfigOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Generate a config first.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpTextarea.value).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('mdwintConfigStatus', '.meadow.config.json copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tcopyMdwintCLI()\n\t{\n\t\tlet tmpCmd = document.getElementById('mdwintCLICommand').querySelector('div').textContent;\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpCmd).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'mdwint CLI command copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\tdownloadMdwintConfig()\n\t{\n\t\tlet tmpTextarea = document.getElementById('mdwintConfigOutput');\n\t\tif (!tmpTextarea.value)\n\t\t{\n\t\t\tthis.generateConfig();\n\t\t}\n\t\tlet tmpBlob = new Blob([tmpTextarea.value], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\ttmpAnchor.download = '.meadow.config.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('mdwintConfigStatus', 'Config downloaded as .meadow.config.json.', 'ok');\n\t}\n}\n\nmodule.exports = DataClonerExportView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Export',\n\tDefaultRenderable: 'DataCloner-Export',\n\tDefaultDestinationAddress: '#DataCloner-Section-Export',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Export',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">6</div>\n\t<div class=\"accordion-card\" id=\"section6\" data-section=\"6\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section6')\">\n\t\t\t<div class=\"accordion-title\">Export Configuration</div>\n\t\t\t<div class=\"accordion-preview\" id=\"preview6\">Generate JSON config for headless cloning</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<p style=\"font-size:0.9em; color:#666; margin-bottom:10px\">Generate a JSON config file from your current settings. Use it to run headless clones from the command line.</p>\n\t\t\t<div style=\"display:flex; gap:8px; margin-bottom:10px\">\n\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Export'].generateConfig()\">Generate Config</button>\n\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].copyConfig()\">Copy to Clipboard</button>\n\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].downloadConfig()\">Download JSON</button>\n\t\t\t</div>\n\t\t\t<div id=\"configExportStatus\"></div>\n\t\t\t<div id=\"cliCommand\" style=\"display:none; margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:4px\">CLI Command <span style=\"color:#888; font-weight:normal\">(with config file)</span></label>\n\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer\" onclick=\"pict.views['DataCloner-Export'].copyCLI()\" title=\"Click to copy\"></div>\n\t\t\t</div>\n\t\t\t<div id=\"cliOneShot\" style=\"display:none; margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:4px\">One-liner <span style=\"color:#888; font-weight:normal\">(no config file needed)</span></label>\n\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer; white-space:pre-wrap\" onclick=\"pict.views['DataCloner-Export'].copyOneShot()\" title=\"Click to copy\"></div>\n\t\t\t</div>\n\t\t\t<textarea id=\"configOutput\" style=\"display:none; width:100%; min-height:300px; font-family:monospace; font-size:0.85em; padding:10px; border:1px solid #ccc; border-radius:4px; background:#fafafa; tab-size:4; resize:vertical\" readonly></textarea>\n\n\t\t\t<div id=\"mdwintExport\" style=\"display:none; margin-top:16px; padding-top:16px; border-top:1px solid #eee\">\n\t\t\t\t<h3 style=\"margin:0 0 8px; font-size:1em\">meadow-integration CLI <span style=\"color:#888; font-weight:normal; font-size:0.85em\">(mdwint clone)</span></h3>\n\t\t\t\t<p style=\"font-size:0.85em; color:#666; margin-bottom:8px\">Save as <code>.meadow.config.json</code> in your project root, then run the command below. Requires a local Meadow extended schema JSON file.</p>\n\t\t\t\t<div style=\"display:flex; gap:8px; margin-bottom:10px\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].copyMdwintConfig()\">Copy Config</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Export'].downloadMdwintConfig()\">Download .meadow.config.json</button>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"mdwintCLICommand\" style=\"margin-bottom:10px\">\n\t\t\t\t\t<label style=\"margin-bottom:4px\">CLI Command</label>\n\t\t\t\t\t<div style=\"background:#1a1a1a; color:#4fc3f7; padding:10px 14px; border-radius:4px; font-family:monospace; font-size:0.9em; word-break:break-all; cursor:pointer\" onclick=\"pict.views['DataCloner-Export'].copyMdwintCLI()\" title=\"Click to copy\"></div>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"mdwintConfigStatus\"></div>\n\t\t\t\t<textarea id=\"mdwintConfigOutput\" style=\"width:100%; min-height:250px; font-family:monospace; font-size:0.85em; padding:10px; border:1px solid #ccc; border-radius:4px; background:#fafafa; tab-size:4; resize:vertical\" readonly></textarea>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Export',\n\t\t\tTemplateHash: 'DataCloner-Export',\n\t\t\tDestinationAddress: '#DataCloner-Section-Export'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerLayoutView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tonAfterRender()\n\t{\n\t\t// Render all section views into their containers\n\t\tthis.pict.views['DataCloner-Connection'].render();\n\t\tthis.pict.views['DataCloner-Session'].render();\n\t\tthis.pict.views['DataCloner-Schema'].render();\n\t\tthis.pict.views['DataCloner-Deploy'].render();\n\t\tthis.pict.views['DataCloner-Sync'].render();\n\t\tthis.pict.views['DataCloner-Export'].render();\n\t\tthis.pict.views['DataCloner-ViewData'].render();\n\n\t\tthis.pict.CSSMap.injectCSS();\n\t}\n\n\ttoggleSection(pSectionId)\n\t{\n\t\tlet tmpCard = document.getElementById(pSectionId);\n\t\tif (!tmpCard) return;\n\t\ttmpCard.classList.toggle('open');\n\t}\n\n\texpandAllSections()\n\t{\n\t\tlet tmpCards = document.querySelectorAll('.accordion-card');\n\t\tfor (let i = 0; i < tmpCards.length; i++)\n\t\t{\n\t\t\ttmpCards[i].classList.add('open');\n\t\t}\n\t}\n\n\tcollapseAllSections()\n\t{\n\t\tlet tmpCards = document.querySelectorAll('.accordion-card');\n\t\tfor (let i = 0; i < tmpCards.length; i++)\n\t\t{\n\t\t\ttmpCards[i].classList.remove('open');\n\t\t}\n\t}\n\n\ttoggleStatusDetail()\n\t{\n\t\tlet tmpDetail = document.getElementById('liveStatusDetail');\n\t\tlet tmpMeta = document.getElementById('liveStatusMeta');\n\t\tlet tmpMessage = document.getElementById('liveStatusMessage');\n\t\tlet tmpToggle = document.getElementById('liveStatusToggle');\n\t\tlet tmpBar = document.getElementById('liveStatusBar');\n\t\tif (!tmpDetail) return;\n\n\t\tlet tmpIsExpanded = tmpDetail.style.display !== 'none';\n\n\t\tif (tmpIsExpanded)\n\t\t{\n\t\t\ttmpDetail.style.display = 'none';\n\t\t\ttmpMeta.style.display = '';\n\t\t\ttmpMessage.style.display = '';\n\t\t\ttmpToggle.innerHTML = '▼';\n\t\t\ttmpBar.classList.remove('expanded');\n\t\t\tthis.pict.providers.DataCloner.onStatusDetailCollapsed();\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpDetail.style.display = '';\n\t\t\ttmpMeta.style.display = 'none';\n\t\t\ttmpMessage.style.display = 'none';\n\t\t\ttmpToggle.innerHTML = '▲';\n\t\t\ttmpBar.classList.add('expanded');\n\t\t\tthis.pict.providers.DataCloner.onStatusDetailExpanded();\n\t\t}\n\t}\n}\n\nmodule.exports = DataClonerLayoutView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Layout',\n\tDefaultRenderable: 'DataCloner-Layout',\n\tDefaultDestinationAddress: '#DataCloner-Application-Container',\n\tCSS: /*css*/`\n* { box-sizing: border-box; margin: 0; padding: 0; }\nbody { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; color: #333; padding: 20px; }\nh1 { margin-bottom: 20px; color: #1a1a1a; }\nh2 { margin-bottom: 12px; color: #444; font-size: 1.2em; border-bottom: 2px solid #ddd; padding-bottom: 6px; }\n\n.section { background: #fff; border-radius: 8px; padding: 20px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n\n/* Accordion layout */\n.accordion-row { display: flex; gap: 0; margin-bottom: 16px; align-items: stretch; }\n.accordion-number {\n\tflex: 0 0 48px; display: flex; align-items: flex-start; justify-content: center;\n\tpadding-top: 16px; font-size: 1.6em; font-weight: 700; color: #4a90d9;\n\tuser-select: none;\n}\n.accordion-card {\n\tflex: 1; background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n\toverflow: hidden; min-width: 0;\n}\n.accordion-header {\n\tdisplay: flex; align-items: center; padding: 14px 20px; cursor: pointer;\n\tuser-select: none; gap: 12px; transition: background 0.15s; line-height: 1.4;\n}\n.accordion-header:hover { background: #fafafa; }\n.accordion-title { font-weight: 600; color: #333; font-size: 1.05em; white-space: nowrap; }\n.accordion-preview { flex: 1; font-style: italic; color: #888; font-size: 0.9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }\n.accordion-toggle {\n\tflex: 0 0 20px; display: flex; align-items: center; justify-content: center;\n\tborder-radius: 4px; transition: background 0.15s, transform 0.25s; font-size: 0.7em; color: #888;\n}\n.accordion-header:hover .accordion-toggle { background: #eee; color: #555; }\n.accordion-card.open .accordion-toggle { transform: rotate(180deg); }\n.accordion-body { padding: 0 20px 20px; display: none; }\n.accordion-card.open .accordion-body { display: block; }\n.accordion-card.open .accordion-header { border-bottom: 1px solid #eee; }\n.accordion-card.open .accordion-preview { display: none; }\n\n/* Action controls (go link + auto checkbox) */\n.accordion-actions { display: flex; align-items: baseline; gap: 8px; flex-shrink: 0; }\n.accordion-card.open .accordion-actions { display: none; }\n.accordion-go {\n\tfont-size: 0.82em; color: #4a90d9; cursor: pointer; text-decoration: none;\n\tfont-weight: 500; white-space: nowrap; padding: 2px 6px; border-radius: 3px;\n\ttransition: background 0.15s;\n}\n.accordion-go:hover { background: #e8f0fe; text-decoration: underline; }\n.accordion-auto {\n\tfont-size: 0.82em; color: #999; white-space: nowrap; cursor: pointer;\n}\n.accordion-auto .auto-label { display: none; }\n.accordion-auto:hover .auto-label { display: inline; }\n.accordion-auto input[type=\"checkbox\"] { width: auto; margin: 0; cursor: pointer; vertical-align: middle; position: relative; top: 0px; opacity: 0.75; transition: opacity 0.15s; }\n.accordion-auto:hover input[type=\"checkbox\"] { opacity: 1; }\n.accordion-auto:hover { color: #666; }\n\n/* Phase status indicator */\n.accordion-phase {\n\tflex: 0 0 auto; display: none; align-items: center; justify-content: center;\n\tfont-size: 0.85em; line-height: 1;\n}\n.accordion-phase.visible { display: flex; }\n.accordion-phase-ok { color: #28a745; }\n.accordion-phase-error { color: #dc3545; }\n.accordion-phase-busy { color: #28a745; }\n.accordion-phase-busy .phase-spinner {\n\tdisplay: inline-block; width: 14px; height: 14px;\n\tborder: 2px solid #28a745; border-top-color: transparent; border-radius: 50%;\n\tanimation: phase-spin 0.8s linear infinite; vertical-align: middle;\n}\n@keyframes phase-spin {\n\tto { transform: rotate(360deg); }\n}\n\n.accordion-controls {\n\tdisplay: flex; gap: 8px; margin-bottom: 12px; justify-content: flex-end;\n}\n.accordion-controls button {\n\tpadding: 4px 10px; font-size: 0.82em; font-weight: 500; background: none;\n\tborder: 1px solid #ccc; border-radius: 4px; color: #666; cursor: pointer; margin: 0;\n}\n.accordion-controls button:hover { background: #f0f0f0; border-color: #aaa; color: #333; }\n\nlabel { display: block; font-weight: 600; margin-bottom: 4px; font-size: 0.9em; }\ninput[type=\"text\"], input[type=\"password\"], input[type=\"number\"] {\n\twidth: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px;\n\tfont-size: 0.95em; margin-bottom: 10px;\n}\ninput[type=\"text\"]:focus, input[type=\"password\"]:focus, input[type=\"number\"]:focus {\n\toutline: none; border-color: #4a90d9;\n}\n\nbutton {\n\tpadding: 8px 16px; border: none; border-radius: 4px; cursor: pointer;\n\tfont-size: 0.9em; font-weight: 600; margin-right: 8px; margin-bottom: 8px;\n}\nbutton.primary { background: #4a90d9; color: #fff; }\nbutton.primary:hover { background: #357abd; }\nbutton.secondary { background: #6c757d; color: #fff; }\nbutton.secondary:hover { background: #5a6268; }\nbutton.danger { background: #dc3545; color: #fff; }\nbutton.danger:hover { background: #c82333; }\nbutton.success { background: #28a745; color: #fff; }\nbutton.success:hover { background: #218838; }\nbutton:disabled { opacity: 0.5; cursor: not-allowed; }\n\n.status { padding: 8px 12px; border-radius: 4px; margin-top: 10px; font-size: 0.9em; }\n.status.ok { background: #d4edda; color: #155724; }\n.status.error { background: #f8d7da; color: #721c24; }\n.status.info { background: #d1ecf1; color: #0c5460; }\n.status.warn { background: #fff3cd; color: #856404; }\n\n.inline-group { display: flex; gap: 8px; align-items: flex-end; margin-bottom: 10px; }\n.inline-group > div { flex: 1; }\n\na { color: #4a90d9; }\n\nselect { background: #fff; width: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 0.95em; margin-bottom: 10px; }\n\n.checkbox-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }\n.checkbox-row input[type=\"checkbox\"] { width: auto; margin: 0; }\n.checkbox-row label { display: inline; margin: 0; font-weight: normal; cursor: pointer; }\n\n/* Live Status Bar */\n.live-status-bar {\n\tbackground: #fff; border-radius: 8px; margin-bottom: 16px;\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.1);\n\tposition: sticky; top: 0; z-index: 100; border-left: 4px solid #6c757d;\n}\n.live-status-bar.phase-idle { border-left-color: #6c757d; }\n.live-status-bar.phase-disconnected { border-left-color: #dc3545; }\n.live-status-bar.phase-ready { border-left-color: #4a90d9; }\n.live-status-bar.phase-syncing { border-left-color: #28a745; }\n.live-status-bar.phase-stopping { border-left-color: #ffc107; }\n.live-status-bar.phase-complete { border-left-color: #28a745; }\n\n.live-status-dot {\n\twidth: 12px; height: 12px; border-radius: 50%; flex-shrink: 0;\n\tbackground: #6c757d;\n}\n.live-status-bar.phase-idle .live-status-dot { background: #6c757d; }\n.live-status-bar.phase-disconnected .live-status-dot { background: #dc3545; }\n.live-status-bar.phase-ready .live-status-dot { background: #4a90d9; }\n.live-status-bar.phase-syncing .live-status-dot {\n\tbackground: #28a745;\n\tanimation: live-pulse 1.5s ease-in-out infinite;\n}\n.live-status-bar.phase-stopping .live-status-dot {\n\tbackground: #ffc107;\n\tanimation: live-pulse 0.8s ease-in-out infinite;\n}\n.live-status-bar.phase-complete .live-status-dot { background: #28a745; }\n\n@keyframes live-pulse {\n\t0%, 100% { opacity: 1; transform: scale(1); }\n\t50% { opacity: 0.4; transform: scale(0.8); }\n}\n\n.live-status-message { flex: 1; font-size: 0.92em; color: #333; line-height: 1.4; }\n\n.live-status-meta {\n\tdisplay: flex; gap: 16px; flex-shrink: 0; font-size: 0.82em; color: #666;\n}\n.live-status-meta-item { white-space: nowrap; }\n.live-status-meta-item strong { color: #333; }\n\n.live-status-progress-bar {\n\theight: 3px; background: #e9ecef; border-radius: 2px; overflow: hidden;\n\tposition: absolute; bottom: 0; left: 0; right: 0;\n}\n.live-status-progress-fill {\n\theight: 100%; background: #28a745; transition: width 1s ease;\n}\n/* Expandable status bar */\n.live-status-header {\n\tdisplay: flex; align-items: center; gap: 14px; cursor: pointer;\n\tpadding: 14px 20px; user-select: none;\n}\n.live-status-bar.expanded .live-status-header {\n\tborder-bottom: 1px solid #e9ecef; padding-bottom: 10px;\n}\n.live-status-expand-toggle {\n\tflex: 0 0 20px; display: flex; align-items: center; justify-content: center;\n\tfont-size: 0.7em; color: #888; transition: transform 0.25s;\n}\n.live-status-bar.expanded .live-status-expand-toggle { transform: rotate(180deg); }\n\n.live-status-detail {\n\tpadding: 12px 20px 16px; max-height: 60vh; overflow-y: auto;\n}\n\n/* Status Detail Summary Banner */\n.status-detail-summary {\n\tdisplay: flex; align-items: center; gap: 16px; flex-wrap: wrap;\n\tpadding: 8px 0 12px; margin-bottom: 12px; border-bottom: 1px solid #e9ecef;\n}\n.status-detail-summary-message {\n\tfont-size: 0.92em; color: #333; font-weight: 600;\n}\n.status-detail-summary-counters {\n\tdisplay: flex; gap: 16px; flex-wrap: wrap; font-size: 0.82em; color: #666;\n}\n\n/* Status Detail Sections */\n.status-detail-section { margin-bottom: 14px; }\n.status-detail-section:last-child { margin-bottom: 0; }\n.status-detail-section-title {\n\tfont-size: 0.85em; font-weight: 600; color: #555; text-transform: uppercase;\n\tletter-spacing: 0.5px; margin-bottom: 8px; padding-bottom: 4px;\n\tborder-bottom: 1px solid #eee;\n}\n\n/* Running Operations */\n.running-op-row {\n\tdisplay: flex; align-items: center; gap: 12px; padding: 6px 0;\n\tfont-size: 0.9em;\n}\n.running-op-name { font-weight: 600; min-width: 180px; }\n.running-op-bar {\n\tflex: 1; height: 8px; background: #e9ecef; border-radius: 4px; overflow: hidden;\n\tmin-width: 120px;\n}\n.running-op-bar-fill { height: 100%; background: #4a90d9; transition: width 0.5s ease; }\n.running-op-count { font-size: 0.85em; color: #666; white-space: nowrap; }\n.running-op-pending { color: #888; font-size: 0.85em; font-style: italic; padding: 4px 0; }\n\n/* Completed Operations */\n.completed-op-row { padding: 8px 0; border-bottom: 1px solid #f0f0f0; }\n.completed-op-row:last-child { border-bottom: none; }\n.completed-op-header {\n\tdisplay: flex; align-items: center; gap: 10px; font-size: 0.9em; margin-bottom: 4px;\n}\n.completed-op-name { font-weight: 600; }\n.completed-op-stats { color: #666; font-size: 0.85em; }\n.completed-op-checkmark { color: #28a745; }\n\n/* Ratio Bar */\n.ratio-bar-container {\n\tdisplay: flex; height: 10px; border-radius: 5px; overflow: hidden;\n\tbackground: #e9ecef; margin: 4px 0;\n}\n.ratio-bar-segment { height: 100%; transition: width 0.5s ease; }\n.ratio-bar-segment.unchanged { background: #6c757d; }\n.ratio-bar-segment.new-records { background: #28a745; }\n.ratio-bar-segment.updated { background: #4a90d9; }\n.ratio-bar-segment.deleted { background: #dc3545; }\n.ratio-bar-legend {\n\tdisplay: flex; gap: 12px; font-size: 0.75em; color: #666; margin-top: 2px; flex-wrap: wrap;\n}\n.ratio-bar-legend-item { display: flex; align-items: center; gap: 4px; }\n.ratio-bar-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }\n.ratio-bar-legend-dot.unchanged-dot { background: #6c757d; }\n.ratio-bar-legend-dot.new-dot { background: #28a745; }\n.ratio-bar-legend-dot.updated-dot { background: #4a90d9; }\n.ratio-bar-legend-dot.deleted-dot { background: #dc3545; }\n\n/* Error Operations */\n.error-op-row { padding: 6px 0; border-bottom: 1px solid #f0f0f0; font-size: 0.9em; }\n.error-op-row:last-child { border-bottom: none; }\n.error-op-header { display: flex; align-items: center; gap: 8px; }\n.error-op-name { font-weight: 600; color: #dc3545; }\n.error-op-status { font-size: 0.82em; color: #dc3545; }\n.error-op-message { font-size: 0.82em; color: #888; margin-top: 2px; padding-left: 18px; }\n.error-op-log-entries {\n\tfont-size: 0.78em; color: #888; margin-top: 4px; padding-left: 18px;\n\tfont-family: monospace; max-height: 80px; overflow-y: auto;\n}\n\n/* Pre-count Table */\n.precount-table {\n\twidth: 100%; border-collapse: collapse; font-size: 0.88em;\n}\n.precount-table thead th {\n\ttext-align: left; font-weight: 600; color: #555; font-size: 0.85em;\n\ttext-transform: uppercase; letter-spacing: 0.3px;\n\tpadding: 4px 8px 6px; border-bottom: 2px solid #e9ecef;\n}\n.precount-table tbody td {\n\tpadding: 4px 8px; border-bottom: 1px solid #f0f0f0;\n}\n.precount-table tbody tr:last-child td { border-bottom: 1px solid #e9ecef; }\n.precount-table tfoot td {\n\tpadding: 6px 8px 2px; font-size: 0.95em;\n}\n.precount-error td { color: #dc3545; }\n.precount-pending {\n\tcolor: #888; font-size: 0.85em; font-style: italic; padding: 8px 0 2px;\n\tdisplay: flex; align-items: center; gap: 6px;\n}\n.precount-spinner {\n\tdisplay: inline-block; width: 12px; height: 12px;\n\tborder: 2px solid #ddd; border-top-color: #4a90d9;\n\tborder-radius: 50%; animation: precount-spin 0.8s linear infinite;\n}\n@keyframes precount-spin { to { transform: rotate(360deg); } }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Layout',\n\t\t\tTemplate: /*html*/`\n<h1>Retold Data Cloner</h1>\n\n<!-- Live Status Bar (Expandable) -->\n<div id=\"liveStatusBar\" class=\"live-status-bar phase-idle\" style=\"position:relative\">\n\t<div class=\"live-status-header\" onclick=\"pict.views['DataCloner-Layout'].toggleStatusDetail()\">\n\t\t<div class=\"live-status-dot\"></div>\n\t\t<div class=\"live-status-message\" id=\"liveStatusMessage\">Idle</div>\n\t\t<div class=\"live-status-meta\" id=\"liveStatusMeta\"></div>\n\t\t<div class=\"live-status-expand-toggle\" id=\"liveStatusToggle\">▼</div>\n\t</div>\n\t<div class=\"live-status-detail\" id=\"liveStatusDetail\" style=\"display:none\">\n\t\t<div id=\"DataCloner-Throughput-Histogram\"></div>\n\t\t<div id=\"DataCloner-StatusDetail-Container\"></div>\n\t</div>\n\t<div class=\"live-status-progress-bar\"><div class=\"live-status-progress-fill\" id=\"liveStatusProgressFill\" style=\"width:0%\"></div></div>\n</div>\n\n<!-- Expand / Collapse All -->\n<div class=\"accordion-controls\">\n\t<button onclick=\"pict.views['DataCloner-Layout'].expandAllSections()\">Expand All</button>\n\t<button onclick=\"pict.views['DataCloner-Layout'].collapseAllSections()\">Collapse All</button>\n</div>\n\n<!-- Section containers -->\n<div id=\"DataCloner-Section-Connection\"></div>\n<div id=\"DataCloner-Section-Session\"></div>\n<div id=\"DataCloner-Section-Schema\"></div>\n<div id=\"DataCloner-Section-Deploy\"></div>\n<div id=\"DataCloner-Section-Sync\"></div>\n<div id=\"DataCloner-Section-Export\"></div>\n<div id=\"DataCloner-Section-ViewData\"></div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Layout',\n\t\t\tTemplateHash: 'DataCloner-Layout',\n\t\t\tDestinationAddress: '#DataCloner-Application-Container'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerSchemaView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tfetchSchema()\n\t{\n\t\tlet tmpSchemaURL = document.getElementById('schemaURL').value.trim();\n\t\tlet tmpBody = {};\n\t\tif (tmpSchemaURL)\n\t\t{\n\t\t\ttmpBody.SchemaURL = tmpSchemaURL;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetching schema...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/schema/fetch', tmpBody)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.AppData.DataCloner.FetchedTables = pData.Tables || [];\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetched ' + pData.TableCount + ' tables from ' + pData.SchemaURL, 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'ok');\n\t\t\t\t\t\tthis.renderTableList();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Fetch failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('schemaStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(3, 'error');\n\t\t\t\t});\n\t}\n\n\tloadSavedSelections()\n\t{\n\t\ttry\n\t\t{\n\t\t\tlet tmpRaw = localStorage.getItem('dataCloner_selectedTables');\n\t\t\tif (tmpRaw)\n\t\t\t{\n\t\t\t\treturn JSON.parse(tmpRaw);\n\t\t\t}\n\t\t}\n\t\tcatch (pError)\n\t\t{\n\t\t\t/* ignore */\n\t\t}\n\t\treturn null;\n\t}\n\n\tsaveSelections()\n\t{\n\t\tlet tmpSelected = this.getSelectedTables();\n\t\tlocalStorage.setItem('dataCloner_selectedTables', JSON.stringify(tmpSelected));\n\t\tthis.updateSelectionCount();\n\t\tthis.pict.providers.DataCloner.updateAllPreviews();\n\t}\n\n\tupdateSelectionCount()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpCount = this.getSelectedTables().length;\n\t\tlet tmpEl = document.getElementById('tableSelectionCount');\n\t\tif (tmpEl)\n\t\t{\n\t\t\ttmpEl.textContent = tmpCount + ' / ' + tmpFetchedTables.length + ' selected';\n\t\t}\n\t}\n\n\trenderTableList()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpContainer = document.getElementById('tableList');\n\t\ttmpContainer.innerHTML = '';\n\n\t\t// Load previously saved selections; if none, default to none checked\n\t\tlet tmpSaved = this.loadSavedSelections();\n\t\tlet tmpSavedSet = null;\n\t\tif (tmpSaved)\n\t\t{\n\t\t\ttmpSavedSet = {};\n\t\t\tfor (let i = 0; i < tmpSaved.length; i++)\n\t\t\t{\n\t\t\t\ttmpSavedSet[tmpSaved[i]] = true;\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpFetchedTables[i];\n\t\t\tlet tmpDiv = document.createElement('div');\n\t\t\ttmpDiv.className = 'table-item';\n\t\t\ttmpDiv.setAttribute('data-table', tmpName.toLowerCase());\n\n\t\t\tlet tmpCheckbox = document.createElement('input');\n\t\t\ttmpCheckbox.type = 'checkbox';\n\t\t\ttmpCheckbox.id = 'tbl_' + tmpName;\n\t\t\ttmpCheckbox.value = tmpName;\n\t\t\t// If we have saved selections, restore them; otherwise default unchecked\n\t\t\ttmpCheckbox.checked = tmpSavedSet ? (tmpSavedSet[tmpName] === true) : false;\n\t\t\ttmpCheckbox.addEventListener('change', () => { this.saveSelections(); });\n\n\t\t\tlet tmpLabel = document.createElement('label');\n\t\t\ttmpLabel.htmlFor = 'tbl_' + tmpName;\n\t\t\ttmpLabel.textContent = tmpName;\n\n\t\t\ttmpDiv.appendChild(tmpCheckbox);\n\t\t\ttmpDiv.appendChild(tmpLabel);\n\t\t\ttmpContainer.appendChild(tmpDiv);\n\t\t}\n\n\t\tdocument.getElementById('tableSelection').style.display = tmpFetchedTables.length > 0 ? 'block' : 'none';\n\t\tdocument.getElementById('tableFilter').value = '';\n\t\tthis.updateSelectionCount();\n\t}\n\n\tfilterTableList()\n\t{\n\t\tlet tmpFilter = document.getElementById('tableFilter').value.toLowerCase().trim();\n\t\tlet tmpItems = document.getElementById('tableList').children;\n\t\tfor (let i = 0; i < tmpItems.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpItems[i].getAttribute('data-table') || '';\n\t\t\ttmpItems[i].style.display = (!tmpFilter || tmpName.indexOf(tmpFilter) >= 0) ? '' : 'none';\n\t\t}\n\t}\n\n\tselectAllTables(pChecked)\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\t// Only affect visible (non-filtered) items\n\t\tlet tmpFilter = document.getElementById('tableFilter').value.toLowerCase().trim();\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpFetchedTables[i];\n\t\t\tif (tmpFilter && tmpName.toLowerCase().indexOf(tmpFilter) < 0)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet tmpCheckbox = document.getElementById('tbl_' + tmpName);\n\t\t\tif (tmpCheckbox)\n\t\t\t{\n\t\t\t\ttmpCheckbox.checked = pChecked;\n\t\t\t}\n\t\t}\n\t\tthis.saveSelections();\n\t}\n\n\tgetSelectedTables()\n\t{\n\t\tlet tmpFetchedTables = this.pict.AppData.DataCloner.FetchedTables || [];\n\t\tlet tmpSelected = [];\n\t\tfor (let i = 0; i < tmpFetchedTables.length; i++)\n\t\t{\n\t\t\tlet tmpCheckbox = document.getElementById('tbl_' + tmpFetchedTables[i]);\n\t\t\tif (tmpCheckbox && tmpCheckbox.checked)\n\t\t\t{\n\t\t\t\ttmpSelected.push(tmpFetchedTables[i]);\n\t\t\t}\n\t\t}\n\t\treturn tmpSelected;\n\t}\n}\n\nmodule.exports = DataClonerSchemaView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Schema',\n\tDefaultRenderable: 'DataCloner-Schema',\n\tDefaultDestinationAddress: '#DataCloner-Section-Schema',\n\tCSS: /*css*/`\n.table-list { max-height: 300px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 8px; margin: 10px 0; }\n.table-item { padding: 4px 8px; display: flex; align-items: center; }\n.table-item:hover { background: #f0f0f0; }\n.table-item input[type=\"checkbox\"] { margin-right: 8px; width: auto; }\n.table-item label { display: inline; font-weight: normal; margin-bottom: 0; cursor: pointer; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Schema',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">3</div>\n\t<div class=\"accordion-card\" id=\"section3\" data-section=\"3\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section3')\">\n\t\t\t<div class=\"accordion-title\">Remote Schema</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase3\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview3\">Fetch and select tables from the remote server</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Schema'].fetchSchema()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto3\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<label for=\"schemaURL\">Schema URL (leave blank for default: /1.0/Retold/Models)</label>\n\t\t\t<input type=\"text\" id=\"schemaURL\" placeholder=\"http://remote-server:8086/1.0/Retold/Models\">\n\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Schema'].fetchSchema()\">Fetch Schema</button>\n\t\t\t<div id=\"schemaStatus\"></div>\n\n\t\t\t<div id=\"tableSelection\" style=\"display:none\">\n\t\t\t\t<h3 style=\"margin:12px 0 8px; font-size:1em;\">Select Tables</h3>\n\t\t\t\t<div style=\"display:flex; gap:8px; align-items:center; margin-bottom:8px\">\n\t\t\t\t\t<input type=\"text\" id=\"tableFilter\" placeholder=\"Filter tables...\" style=\"flex:1; margin-bottom:0\" oninput=\"pict.views['DataCloner-Schema'].filterTableList()\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Schema'].selectAllTables(true)\" style=\"font-size:0.8em\">Select All</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Schema'].selectAllTables(false)\" style=\"font-size:0.8em\">Deselect All</button>\n\t\t\t\t\t<span id=\"tableSelectionCount\" style=\"font-size:0.85em; color:#666; white-space:nowrap\"></span>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"tableList\" class=\"table-list\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Schema',\n\t\t\tTemplateHash: 'DataCloner-Schema',\n\t\t\tDestinationAddress: '#DataCloner-Section-Schema'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerSessionView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tconfigureSession()\n\t{\n\t\tlet tmpServerURL = document.getElementById('serverURL').value.trim();\n\t\tif (!tmpServerURL)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Server URL is required.', 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tlet tmpBody = { ServerURL: tmpServerURL.replace(/\\/+$/, '') + '/1.0/' };\n\n\t\tlet tmpAuthMethod = document.getElementById('authMethod').value.trim();\n\t\tif (tmpAuthMethod)\n\t\t{\n\t\t\ttmpBody.AuthenticationMethod = tmpAuthMethod;\n\t\t}\n\n\t\tlet tmpAuthURI = document.getElementById('authURI').value.trim();\n\t\tif (tmpAuthURI)\n\t\t{\n\t\t\ttmpBody.AuthenticationURITemplate = tmpAuthURI;\n\t\t}\n\n\t\tlet tmpCheckURI = document.getElementById('checkURI').value.trim();\n\t\tif (tmpCheckURI)\n\t\t{\n\t\t\ttmpBody.CheckSessionURITemplate = tmpCheckURI;\n\t\t}\n\n\t\tlet tmpCookieName = document.getElementById('cookieName').value.trim();\n\t\tif (tmpCookieName)\n\t\t{\n\t\t\ttmpBody.CookieName = tmpCookieName;\n\t\t}\n\n\t\tlet tmpCookieValueAddr = document.getElementById('cookieValueAddr').value.trim();\n\t\tif (tmpCookieValueAddr)\n\t\t{\n\t\t\ttmpBody.CookieValueAddress = tmpCookieValueAddr;\n\t\t}\n\n\t\tlet tmpCookieValueTemplate = document.getElementById('cookieValueTemplate').value.trim();\n\t\tif (tmpCookieValueTemplate)\n\t\t{\n\t\t\ttmpBody.CookieValueTemplate = tmpCookieValueTemplate;\n\t\t}\n\n\t\tlet tmpLoginMarker = document.getElementById('loginMarker').value.trim();\n\t\tif (tmpLoginMarker)\n\t\t{\n\t\t\ttmpBody.CheckSessionLoginMarker = tmpLoginMarker;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Configuring session...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/configure', tmpBody)\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Session configured for ' + pData.ServerURL + ' (domain: ' + pData.DomainMatch + ')', 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Configuration failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionConfigStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tauthenticate()\n\t{\n\t\tlet tmpUserName = document.getElementById('userName').value.trim();\n\t\tlet tmpPassword = document.getElementById('password').value.trim();\n\n\t\tif (!tmpUserName || !tmpPassword)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Username and password are required.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authenticating...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/authenticate', { UserName: tmpUserName, Password: tmpPassword })\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Success && pData.Authenticated)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authenticated successfully.', 'ok');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Authentication failed: ' + (pData.Error || 'Not authenticated'), 'error');\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'error');\n\t\t\t\t});\n\t}\n\n\tcheckSession()\n\t{\n\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Checking session...', 'info');\n\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/session/check')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tif (pData.Authenticated)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session is active. Server: ' + (pData.ServerURL || 'N/A'), 'ok');\n\t\t\t\t\t}\n\t\t\t\t\telse if (pData.Configured)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session configured but not authenticated.', 'warn');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'No session configured.', 'warn');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tdeauthenticate()\n\t{\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/session/deauthenticate')\n\t\t\t.then(\n\t\t\t\t(pData) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Session deauthenticated.', 'info');\n\t\t\t\t})\n\t\t\t.catch(\n\t\t\t\t(pError) =>\n\t\t\t\t{\n\t\t\t\t\tthis.pict.providers.DataCloner.setStatus('sessionAuthStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\t});\n\t}\n\n\tgoAction()\n\t{\n\t\t// Two-step: configure session, then authenticate after delay\n\t\tthis.pict.providers.DataCloner.setSectionPhase(2, 'busy');\n\t\tthis.configureSession();\n\t\tsetTimeout(\n\t\t\t() =>\n\t\t\t{\n\t\t\t\tthis.authenticate();\n\t\t\t}, 1500);\n\t}\n}\n\nmodule.exports = DataClonerSessionView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Session',\n\tDefaultRenderable: 'DataCloner-Session',\n\tDefaultDestinationAddress: '#DataCloner-Section-Session',\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Session',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">2</div>\n\t<div class=\"accordion-card\" id=\"section2\" data-section=\"2\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section2')\">\n\t\t\t<div class=\"accordion-title\">Remote Session</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase2\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview2\">Configure remote server URL and credentials</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Session'].goAction()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto2\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:2\">\n\t\t\t\t\t<label for=\"serverURL\">Remote Server URL</label>\n\t\t\t\t\t<input type=\"text\" id=\"serverURL\" placeholder=\"http://remote-server:8086\" value=\"\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t<label for=\"authMethod\">Auth Method</label>\n\t\t\t\t\t<input type=\"text\" id=\"authMethod\" placeholder=\"get\" value=\"get\">\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<details style=\"margin-bottom:10px\">\n\t\t\t\t<summary style=\"cursor:pointer; font-size:0.9em; color:#666\">Advanced Session Options</summary>\n\t\t\t\t<div style=\"padding:10px 0\">\n\t\t\t\t\t<label for=\"authURI\">Authentication URI Template (leave blank for default)</label>\n\t\t\t\t\t<input type=\"text\" id=\"authURI\" placeholder=\"Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}\">\n\t\t\t\t\t<label for=\"checkURI\">Check Session URI Template</label>\n\t\t\t\t\t<input type=\"text\" id=\"checkURI\" placeholder=\"CheckSession\">\n\t\t\t\t\t<label for=\"cookieName\">Cookie Name</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieName\" placeholder=\"SessionID\" value=\"SessionID\">\n\t\t\t\t\t<label for=\"cookieValueAddr\">Cookie Value Address</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieValueAddr\" placeholder=\"SessionID\" value=\"SessionID\">\n\t\t\t\t\t<label for=\"cookieValueTemplate\">Cookie Value Template (overrides Address if set)</label>\n\t\t\t\t\t<input type=\"text\" id=\"cookieValueTemplate\" placeholder=\"{~D:Record.SessionID~}\">\n\t\t\t\t\t<label for=\"loginMarker\">Login Marker</label>\n\t\t\t\t\t<input type=\"text\" id=\"loginMarker\" placeholder=\"LoggedIn\" value=\"LoggedIn\">\n\t\t\t\t</div>\n\t\t\t</details>\n\n\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-Session'].configureSession()\">Configure Session</button>\n\t\t\t<div id=\"sessionConfigStatus\"></div>\n\n\t\t\t<hr style=\"margin:16px 0; border:none; border-top:1px solid #eee\">\n\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div>\n\t\t\t\t\t<label for=\"userName\">Username</label>\n\t\t\t\t\t<input type=\"text\" id=\"userName\" placeholder=\"username\">\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<label for=\"password\">Password</label>\n\t\t\t\t\t<input type=\"password\" id=\"password\" placeholder=\"password\">\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<button class=\"success\" onclick=\"pict.views['DataCloner-Session'].authenticate()\">Authenticate</button>\n\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Session'].checkSession()\">Check Session</button>\n\t\t\t<button class=\"danger\" onclick=\"pict.views['DataCloner-Session'].deauthenticate()\">Deauthenticate</button>\n\t\t\t<div id=\"sessionAuthStatus\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Session',\n\t\t\tTemplateHash: 'DataCloner-Session',\n\t\t\tDestinationAddress: '#DataCloner-Section-Session'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerSyncView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tstartSync()\n\t{\n\t\tlet tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();\n\t\tlet tmpPageSize = parseInt(document.getElementById('pageSize').value, 10) || 100;\n\t\tlet tmpDateTimePrecisionMS = parseInt(document.getElementById('dateTimePrecisionMS').value, 10);\n\t\tif (isNaN(tmpDateTimePrecisionMS)) tmpDateTimePrecisionMS = 1000;\n\t\tlet tmpSyncDeletedRecords = document.getElementById('syncDeletedRecords').checked;\n\t\tlet tmpSyncMode = document.querySelector('input[name=\"syncMode\"]:checked').value;\n\t\tlet tmpMaxRecords = parseInt(document.getElementById('syncMaxRecords').value, 10) || 0;\n\t\tlet tmpLogToFile = document.getElementById('syncLogFile').checked;\n\t\tlet tmpAdvancedIDPagination = document.getElementById('syncAdvancedIDPagination').checked;\n\n\t\tif (tmpSelectedTables.length === 0)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('syncStatus', 'No tables selected for sync.', 'error');\n\t\t\tthis.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setSectionPhase(5, 'busy');\n\t\tthis.pict.providers.DataCloner.setStatus('syncStatus', 'Starting ' + tmpSyncMode.toLowerCase() + ' sync...', 'info');\n\n\t\tlet tmpSelf = this;\n\t\tlet tmpPostBody = { Tables: tmpSelectedTables, PageSize: tmpPageSize, DateTimePrecisionMS: tmpDateTimePrecisionMS, SyncDeletedRecords: tmpSyncDeletedRecords, SyncMode: tmpSyncMode };\n\t\tif (tmpMaxRecords > 0) tmpPostBody.MaxRecordsPerEntity = tmpMaxRecords;\n\t\tif (tmpLogToFile) tmpPostBody.LogToFile = true;\n\t\tif (tmpAdvancedIDPagination) tmpPostBody.UseAdvancedIDPagination = true;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/sync/start', tmpPostBody)\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData.Success)\n\t\t\t\t{\n\t\t\t\t\tlet tmpMsg = pData.SyncMode + ' sync started for ' + pData.Tables.length + ' tables.';\n\t\t\t\t\tif (pData.SyncDeletedRecords) tmpMsg += ' (including deleted records)';\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', tmpMsg, 'ok');\n\t\t\t\t\ttmpSelf.startPolling();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync start failed: ' + (pData.Error || 'Unknown error'), 'error');\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t});\n\t}\n\n\tstopSync()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('POST', '/clone/sync/stop')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync stop requested.', 'warn');\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n\n\tstartPolling()\n\t{\n\t\tif (this.pict.AppData.DataCloner.SyncPollTimer) clearInterval(this.pict.AppData.DataCloner.SyncPollTimer);\n\t\tlet tmpSelf = this;\n\t\tthis.pict.AppData.DataCloner.SyncPollTimer = setInterval(function() { tmpSelf.pollSyncStatus(); }, 2000);\n\t\tthis.pollSyncStatus();\n\t}\n\n\tstopPolling()\n\t{\n\t\tif (this.pict.AppData.DataCloner.SyncPollTimer)\n\t\t{\n\t\t\tclearInterval(this.pict.AppData.DataCloner.SyncPollTimer);\n\t\t\tthis.pict.AppData.DataCloner.SyncPollTimer = null;\n\t\t}\n\t}\n\n\tpollSyncStatus()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/sync/status')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\ttmpSelf.renderSyncProgress(pData);\n\n\t\t\t\tif (!pData.Running && !pData.Stopping)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.stopPolling();\n\t\t\t\t\tif (Object.keys(pData.Tables || {}).length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if any tables had errors or partial sync\n\t\t\t\t\t\tlet tmpTables = pData.Tables || {};\n\t\t\t\t\t\tlet tmpHasErrors = false;\n\t\t\t\t\t\tlet tmpHasPartial = false;\n\t\t\t\t\t\tlet tmpNames = Object.keys(tmpTables);\n\t\t\t\t\t\tfor (let i = 0; i < tmpNames.length; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpTables[tmpNames[i]].Status === 'Error') tmpHasErrors = true;\n\t\t\t\t\t\t\tif (tmpTables[tmpNames[i]].Status === 'Partial') tmpHasPartial = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (tmpHasErrors)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync finished with errors. Check the table below for details.', 'error');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'error');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (tmpHasPartial)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync finished. Some records were skipped (GUID conflicts or permission issues).', 'warn');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'ok');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('syncStatus', 'Sync complete.', 'ok');\n\t\t\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setSectionPhase(5, 'ok');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Fetch the structured report\n\t\t\t\t\t\ttmpSelf.fetchSyncReport();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\t// Silently ignore poll errors\n\t\t\t});\n\t}\n\n\tfetchSyncReport()\n\t{\n\t\tlet tmpSelf = this;\n\t\tthis.pict.providers.DataCloner.api('GET', '/clone/sync/report')\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (pData && pData.ReportVersion)\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.AppData.DataCloner.LastReport = pData;\n\t\t\t\t\ttmpSelf.renderSyncReport(pData);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\t// Ignore report fetch errors\n\t\t\t});\n\t}\n\n\trenderSyncReport(pReport)\n\t{\n\t\tlet tmpSection = document.getElementById('syncReportSection');\n\t\ttmpSection.style.display = '';\n\n\t\t// --- Summary Cards ---\n\t\tlet tmpCardsContainer = document.getElementById('reportSummaryCards');\n\t\tlet tmpOutcomeClass = 'outcome-' + pReport.Outcome.toLowerCase();\n\t\tlet tmpOutcomeColor = { Success: '#28a745', Partial: '#ffc107', Error: '#dc3545', Stopped: '#6c757d' }[pReport.Outcome] || '#666';\n\n\t\tlet tmpDurationSec = pReport.RunTimestamps.DurationSeconds || 0;\n\t\tlet tmpDurationStr = tmpDurationSec < 60 ? tmpDurationSec + 's' : Math.floor(tmpDurationSec / 60) + 'm ' + (tmpDurationSec % 60) + 's';\n\n\t\tlet tmpTotalSynced = pReport.Summary.TotalSynced.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\tlet tmpTotalRecords = pReport.Summary.TotalRecords.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\n\t\ttmpCardsContainer.innerHTML = ''\n\t\t\t+ '<div class=\"report-card ' + tmpOutcomeClass + '\">'\n\t\t\t+ ' <div class=\"card-label\">Outcome</div>'\n\t\t\t+ ' <div class=\"card-value\" style=\"color:' + tmpOutcomeColor + '\">' + pReport.Outcome + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Mode</div>'\n\t\t\t+ ' <div class=\"card-value\">' + pReport.Config.SyncMode + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Duration</div>'\n\t\t\t+ ' <div class=\"card-value\">' + tmpDurationStr + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Tables</div>'\n\t\t\t+ ' <div class=\"card-value\">' + pReport.Summary.Complete + ' / ' + pReport.Summary.TotalTables + '</div>'\n\t\t\t+ '</div>'\n\t\t\t+ '<div class=\"report-card\">'\n\t\t\t+ ' <div class=\"card-label\">Records</div>'\n\t\t\t+ ' <div class=\"card-value\">' + tmpTotalSynced + '</div>'\n\t\t\t+ ' <div style=\"font-size:0.75em; color:#888\">of ' + tmpTotalRecords + '</div>'\n\t\t\t+ '</div>';\n\n\t\t// --- Anomalies ---\n\t\tlet tmpAnomalyContainer = document.getElementById('reportAnomalies');\n\t\tif (pReport.Anomalies.length === 0)\n\t\t{\n\t\t\ttmpAnomalyContainer.innerHTML = '<div style=\"color:#28a745; font-weight:600; font-size:0.9em\">No anomalies detected.</div>';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlet tmpHtml = '<h4 style=\"margin:0 0 8px; color:#dc3545; font-size:0.95em\">Anomalies (' + pReport.Anomalies.length + ')</h4>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Type</th><th>Message</th></tr>';\n\t\t\tfor (let i = 0; i < pReport.Anomalies.length; i++)\n\t\t\t{\n\t\t\t\tlet tmpAnomaly = pReport.Anomalies[i];\n\t\t\t\tlet tmpTypeColor = tmpAnomaly.Type === 'Error' ? '#dc3545' : (tmpAnomaly.Type === 'Partial' ? '#ffc107' : '#6c757d');\n\t\t\t\ttmpHtml += '<tr>';\n\t\t\t\ttmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Table) + '</strong></td>';\n\t\t\t\ttmpHtml += '<td style=\"color:' + tmpTypeColor + '\">' + tmpAnomaly.Type + '</td>';\n\t\t\t\ttmpHtml += '<td>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Message) + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\ttmpAnomalyContainer.innerHTML = tmpHtml;\n\t\t}\n\n\t\t// --- Top Tables by Duration ---\n\t\tlet tmpTopContainer = document.getElementById('reportTopTables');\n\t\tlet tmpTopCount = Math.min(10, pReport.Tables.length);\n\t\tif (tmpTopCount > 0)\n\t\t{\n\t\t\tlet tmpHtml = '<h4 style=\"margin:0 0 8px; font-size:0.95em; color:#444\">Top Tables by Duration</h4>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Duration</th><th>Records</th><th>Status</th></tr>';\n\t\t\tfor (let i = 0; i < tmpTopCount; i++)\n\t\t\t{\n\t\t\t\tlet tmpTable = pReport.Tables[i];\n\t\t\t\tlet tmpDur = tmpTable.DurationSeconds < 60 ? tmpTable.DurationSeconds + 's' : Math.floor(tmpTable.DurationSeconds / 60) + 'm ' + (tmpTable.DurationSeconds % 60) + 's';\n\t\t\t\tlet tmpRecs = tmpTable.Total.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\t\t\t\tlet tmpStatusColor = { Complete: '#28a745', Error: '#dc3545', Partial: '#ffc107' }[tmpTable.Status] || '#666';\n\t\t\t\ttmpHtml += '<tr>';\n\t\t\t\ttmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpTable.Name) + '</strong></td>';\n\t\t\t\ttmpHtml += '<td>' + tmpDur + '</td>';\n\t\t\t\ttmpHtml += '<td>' + tmpRecs + '</td>';\n\t\t\t\ttmpHtml += '<td style=\"color:' + tmpStatusColor + '\">' + tmpTable.Status + '</td>';\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\ttmpTopContainer.innerHTML = tmpHtml;\n\t\t}\n\t}\n\n\tdownloadReport()\n\t{\n\t\tif (!this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'No report available.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpJson = JSON.stringify(this.pict.AppData.DataCloner.LastReport, null, '\\t');\n\t\tlet tmpBlob = new Blob([tmpJson], { type: 'application/json' });\n\t\tlet tmpAnchor = document.createElement('a');\n\t\ttmpAnchor.href = URL.createObjectURL(tmpBlob);\n\t\tlet tmpTimestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n\t\ttmpAnchor.download = 'DataCloner-Report-' + tmpTimestamp + '.json';\n\t\ttmpAnchor.click();\n\t\tURL.revokeObjectURL(tmpAnchor.href);\n\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'Report downloaded.', 'ok');\n\t}\n\n\tcopyReport()\n\t{\n\t\tif (!this.pict.AppData.DataCloner.LastReport)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('reportStatus', 'No report available.', 'warn');\n\t\t\treturn;\n\t\t}\n\t\tlet tmpJson = JSON.stringify(this.pict.AppData.DataCloner.LastReport, null, '\\t');\n\t\tlet tmpSelf = this;\n\t\tnavigator.clipboard.writeText(tmpJson).then(function()\n\t\t{\n\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('reportStatus', 'Report copied to clipboard.', 'ok');\n\t\t});\n\t}\n\n\trenderSyncProgress(pData)\n\t{\n\t\tlet tmpContainer = document.getElementById('syncProgress');\n\t\tlet tmpTables = pData.Tables || {};\n\t\tlet tmpTableNames = Object.keys(tmpTables);\n\n\t\tif (tmpTableNames.length === 0)\n\t\t{\n\t\t\ttmpContainer.innerHTML = '';\n\t\t\treturn;\n\t\t}\n\n\t\t// Categorize tables into sections, preserving original order for pending\n\t\tlet tmpSyncing = [];\n\t\tlet tmpPending = [];\n\t\tlet tmpCompleted = [];\n\t\tlet tmpErrors = [];\n\n\t\tfor (let i = 0; i < tmpTableNames.length; i++)\n\t\t{\n\t\t\tlet tmpName = tmpTableNames[i];\n\t\t\tlet tmpTable = tmpTables[tmpName];\n\n\t\t\tif (tmpTable.Status === 'Syncing')\n\t\t\t{\n\t\t\t\ttmpSyncing.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse if (tmpTable.Status === 'Pending')\n\t\t\t{\n\t\t\t\ttmpPending.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse if (tmpTable.Status === 'Complete')\n\t\t\t{\n\t\t\t\ttmpCompleted.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Error, Partial, or anything else\n\t\t\t\ttmpErrors.push({ Name: tmpName, Data: tmpTable });\n\t\t\t}\n\t\t}\n\n\t\tlet tmpHtml = '';\n\t\tlet tmpSelf = this;\n\t\tlet fRenderRow = (pName, pTable) =>\n\t\t{\n\t\t\t// Calculate percentage\n\t\t\tlet tmpPct = 0;\n\t\t\tif (pTable.Total === 0 && (pTable.Status === 'Complete' || pTable.Status === 'Error'))\n\t\t\t{\n\t\t\t\ttmpPct = 100;\n\t\t\t}\n\t\t\telse if (pTable.Total > 0)\n\t\t\t{\n\t\t\t\ttmpPct = Math.round((pTable.Synced / pTable.Total) * 100);\n\t\t\t}\n\n\t\t\t// Color the progress bar based on status\n\t\t\tlet tmpBarColor = '#28a745'; // green\n\t\t\tif (pTable.Status === 'Error') tmpBarColor = '#dc3545';\n\t\t\telse if (pTable.Status === 'Partial') tmpBarColor = '#ffc107';\n\t\t\telse if (pTable.Status === 'Syncing') tmpBarColor = '#4a90d9';\n\t\t\telse if (pTable.Status === 'Pending') tmpBarColor = '#adb5bd';\n\n\t\t\t// Status badge\n\t\t\tlet tmpStatusBadge = pTable.Status;\n\t\t\tif (pTable.Status === 'Complete' && pTable.Total === 0) tmpStatusBadge = 'Complete (empty)';\n\t\t\tif (pTable.Status === 'Partial') tmpStatusBadge = 'Partial \\u26A0';\n\t\t\tif (pTable.Status === 'Error') tmpStatusBadge = 'Error \\u2716';\n\n\t\t\t// Details column\n\t\t\tlet tmpDetails = '';\n\t\t\tif (pTable.ErrorMessage) tmpDetails = pTable.ErrorMessage;\n\t\t\telse if (pTable.Skipped > 0) tmpDetails = pTable.Skipped + ' record(s) skipped';\n\t\t\telse if ((pTable.Errors || 0) > 0) tmpDetails = pTable.Errors + ' error(s)';\n\t\t\telse if (pTable.Status === 'Complete' && pTable.Total === 0) tmpDetails = 'No records on server';\n\t\t\telse if (pTable.Status === 'Complete') tmpDetails = '\\u2714 OK';\n\n\t\t\tlet tmpRow = '<tr>';\n\t\t\ttmpRow += '<td><strong>' + pName + '</strong></td>';\n\t\t\ttmpRow += '<td>' + tmpStatusBadge + '</td>';\n\t\t\ttmpRow += '<td>';\n\t\t\ttmpRow += '<div class=\"progress-bar-container\"><div class=\"progress-bar-fill\" style=\"width:' + tmpPct + '%; background:' + tmpBarColor + '\"></div></div>';\n\t\t\ttmpRow += ' ' + tmpPct + '%';\n\t\t\ttmpRow += '</td>';\n\t\t\ttmpRow += '<td>' + pTable.Synced + ' / ' + pTable.Total + '</td>';\n\t\t\ttmpRow += '<td>' + tmpDetails + '</td>';\n\t\t\ttmpRow += '</tr>';\n\t\t\treturn tmpRow;\n\t\t};\n\n\t\t// === SYNCING — currently active ===\n\t\tif (tmpSyncing.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header\">Syncing</div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpSyncing.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpSyncing[i].Name, tmpSyncing[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// === NEXT UP — pending tables in queue order ===\n\t\tif (tmpPending.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header\">Next Up <span class=\"sync-section-count\">' + tmpPending.length + '</span></div>';\n\t\t\t// Show at most 8 upcoming; collapse the rest\n\t\t\tlet tmpShowCount = Math.min(8, tmpPending.length);\n\t\t\ttmpHtml += '<table class=\"progress-table progress-table-muted\">';\n\t\t\tfor (let i = 0; i < tmpShowCount; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += '<tr><td>' + tmpPending[i].Name + '</td>';\n\t\t\t\tif (tmpPending[i].Data.Total > 0)\n\t\t\t\t{\n\t\t\t\t\ttmpHtml += '<td class=\"sync-pending-count\">' + tmpPending[i].Data.Total.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + ' records</td>';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttmpHtml += '<td class=\"sync-pending-count\">—</td>';\n\t\t\t\t}\n\t\t\t\ttmpHtml += '</tr>';\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t\tif (tmpPending.length > tmpShowCount)\n\t\t\t{\n\t\t\t\ttmpHtml += '<div class=\"sync-section-overflow\">+ ' + (tmpPending.length - tmpShowCount) + ' more table' + (tmpPending.length - tmpShowCount === 1 ? '' : 's') + '</div>';\n\t\t\t}\n\t\t}\n\n\t\t// === ERRORS — failed or partial ===\n\t\tif (tmpErrors.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header sync-section-header-error\">Errors <span class=\"sync-section-count\">' + tmpErrors.length + '</span></div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpErrors.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpErrors[i].Name, tmpErrors[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\t// === COMPLETED — successful tables ===\n\t\tif (tmpCompleted.length > 0)\n\t\t{\n\t\t\ttmpHtml += '<div class=\"sync-section-header sync-section-header-ok\">Completed <span class=\"sync-section-count\">' + tmpCompleted.length + '</span></div>';\n\t\t\ttmpHtml += '<table class=\"progress-table\">';\n\t\t\ttmpHtml += '<tr><th>Table</th><th>Status</th><th>Progress</th><th>Synced</th><th>Details</th></tr>';\n\t\t\tfor (let i = 0; i < tmpCompleted.length; i++)\n\t\t\t{\n\t\t\t\ttmpHtml += fRenderRow(tmpCompleted[i].Name, tmpCompleted[i].Data);\n\t\t\t}\n\t\t\ttmpHtml += '</table>';\n\t\t}\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\t}\n}\n\nmodule.exports = DataClonerSyncView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-Sync',\n\tDefaultRenderable: 'DataCloner-Sync',\n\tDefaultDestinationAddress: '#DataCloner-Section-Sync',\n\tCSS: /*css*/`\n.progress-table { width: 100%; border-collapse: collapse; margin-top: 4px; margin-bottom: 4px; }\n.progress-table th, .progress-table td { text-align: left; padding: 6px 12px; border-bottom: 1px solid #eee; font-size: 0.9em; }\n.progress-table th { background: #f8f9fa; font-weight: 600; }\n.progress-table-muted td { color: #888; padding: 3px 12px; font-size: 0.85em; border-bottom: 1px solid #f4f5f6; }\n.progress-bar-container { width: 120px; height: 16px; background: #e9ecef; border-radius: 8px; overflow: hidden; display: inline-block; vertical-align: middle; }\n.progress-bar-fill { height: 100%; background: #28a745; transition: width 0.3s; }\n.sync-section-header { font-size: 0.8em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: #4a90d9; padding: 10px 0 2px 0; margin-top: 6px; border-top: 1px solid #e0e0e0; }\n.sync-section-header:first-child { border-top: none; margin-top: 10px; }\n.sync-section-header-error { color: #dc3545; }\n.sync-section-header-ok { color: #28a745; }\n.sync-section-count { font-weight: 400; color: #999; font-size: 0.95em; }\n.sync-section-overflow { font-size: 0.8em; color: #aaa; padding: 2px 12px 6px; }\n.sync-pending-count { text-align: right; color: #aaa; font-size: 0.85em; }\n.report-card { background: #f8f9fa; border-radius: 8px; padding: 12px 16px; min-width: 140px; text-align: center; border: 1px solid #e9ecef; }\n.report-card .card-label { font-size: 0.8em; color: #666; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }\n.report-card .card-value { font-size: 1.4em; font-weight: 700; }\n.report-card.outcome-success { border-left: 4px solid #28a745; }\n.report-card.outcome-partial { border-left: 4px solid #ffc107; }\n.report-card.outcome-error { border-left: 4px solid #dc3545; }\n.report-card.outcome-stopped { border-left: 4px solid #6c757d; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-Sync',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">5</div>\n\t<div class=\"accordion-card\" id=\"section5\" data-section=\"5\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section5')\">\n\t\t\t<div class=\"accordion-title\">Synchronize Data</div>\n\t\t\t<span class=\"accordion-phase\" id=\"phase5\"></span>\n\t\t\t<div class=\"accordion-preview\" id=\"preview5\">Initial sync, page size 100</div>\n\t\t\t<div class=\"accordion-actions\">\n\t\t\t\t<span class=\"accordion-go\" onclick=\"event.stopPropagation(); pict.views['DataCloner-Sync'].startSync()\">go</span>\n\t\t\t\t<label class=\"accordion-auto\" onclick=\"event.stopPropagation()\"><input type=\"checkbox\" id=\"auto5\"> <span class=\"auto-label\">auto</span></label>\n\t\t\t</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div style=\"display:flex; gap:8px; align-items:flex-end; margin-bottom:4px\">\n\t\t\t\t<div style=\"flex:0 0 150px\">\n\t\t\t\t\t<label for=\"pageSize\">Page Size</label>\n\t\t\t\t\t<input type=\"number\" id=\"pageSize\" value=\"100\" min=\"1\" max=\"10000\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 220px\">\n\t\t\t\t\t<label for=\"dateTimePrecisionMS\">Timestamp Precision (ms)</label>\n\t\t\t\t\t<input type=\"number\" id=\"dateTimePrecisionMS\" value=\"1000\" min=\"0\" max=\"60000\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; gap:8px\">\n\t\t\t\t\t<button class=\"success\" style=\"margin:0\" onclick=\"pict.views['DataCloner-Sync'].startSync()\">Start Sync</button>\n\t\t\t\t\t<button class=\"danger\" style=\"margin:0\" onclick=\"pict.views['DataCloner-Sync'].stopSync()\">Stop Sync</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div style=\"font-size:0.8em; color:#888; margin-bottom:10px; padding-left:158px\">Cross-DB tolerance for date comparison (default: 1000ms)</div>\n\n\t\t\t<div style=\"margin-bottom:10px\">\n\t\t\t\t<label style=\"margin-bottom:6px\">Sync Mode</label>\n\t\t\t\t<div style=\"display:flex; gap:16px; align-items:center\">\n\t\t\t\t\t<label style=\"font-weight:normal; margin:0; cursor:pointer\">\n\t\t\t\t\t\t<input type=\"radio\" name=\"syncMode\" id=\"syncModeInitial\" value=\"Initial\" checked> Initial\n\t\t\t\t\t\t<span style=\"color:#888; font-size:0.85em\">(full clone — download all records)</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t<label style=\"font-weight:normal; margin:0; cursor:pointer\">\n\t\t\t\t\t\t<input type=\"radio\" name=\"syncMode\" id=\"syncModeOngoing\" value=\"Ongoing\"> Ongoing\n\t\t\t\t\t\t<span style=\"color:#888; font-size:0.85em\">(delta — only new/updated records since last sync)</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t<input type=\"checkbox\" id=\"syncDeletedRecords\">\n\t\t\t\t<label for=\"syncDeletedRecords\">Sync deleted records (fetch records marked Deleted=1 on source and mirror locally)</label>\n\t\t\t</div>\n\n\t\t\t<div class=\"checkbox-row\">\n\t\t\t\t<input type=\"checkbox\" id=\"syncAdvancedIDPagination\">\n\t\t\t\t<label for=\"syncAdvancedIDPagination\">Use advanced ID pagination (faster for large tables; uses keyset pagination instead of OFFSET)</label>\n\t\t\t</div>\n\n\t\t\t<div class=\"inline-group\" style=\"margin-top:8px; margin-bottom:4px\">\n\t\t\t\t<div style=\"flex:0 0 200px\">\n\t\t\t\t\t<label for=\"syncMaxRecords\">Max Records per Entity</label>\n\t\t\t\t\t<input type=\"number\" id=\"syncMaxRecords\" value=\"\" min=\"0\" placeholder=\"0 = unlimited\" style=\"margin-bottom:0\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; align-items:flex-end; padding-bottom:2px\">\n\t\t\t\t\t<div class=\"checkbox-row\" style=\"margin-bottom:0\">\n\t\t\t\t\t\t<input type=\"checkbox\" id=\"syncLogFile\" checked>\n\t\t\t\t\t\t<label for=\"syncLogFile\">Write log file</label>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div id=\"syncStatus\"></div>\n\t\t\t<div id=\"syncProgress\"></div>\n\n\t\t\t<!-- Sync Report (appears after sync completes) -->\n\t\t\t<div id=\"syncReportSection\" style=\"display:none; margin-top:16px; padding-top:16px; border-top:2px solid #ddd\">\n\t\t\t\t<h3 style=\"margin:0 0 12px; font-size:1.1em\">Sync Report</h3>\n\n\t\t\t\t<!-- Summary cards -->\n\t\t\t\t<div id=\"reportSummaryCards\" style=\"display:flex; gap:12px; flex-wrap:wrap; margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Anomalies -->\n\t\t\t\t<div id=\"reportAnomalies\" style=\"margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Top tables by duration -->\n\t\t\t\t<div id=\"reportTopTables\" style=\"margin-bottom:16px\"></div>\n\n\t\t\t\t<!-- Buttons -->\n\t\t\t\t<div style=\"display:flex; gap:8px\">\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Sync'].downloadReport()\">Download Report JSON</button>\n\t\t\t\t\t<button class=\"secondary\" onclick=\"pict.views['DataCloner-Sync'].copyReport()\">Copy Report</button>\n\t\t\t\t</div>\n\t\t\t\t<div id=\"reportStatus\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-Sync',\n\t\t\tTemplateHash: 'DataCloner-Sync',\n\t\t\tDestinationAddress: '#DataCloner-Section-Sync'\n\t\t}\n\t]\n};\n","const libPictView = require('pict-view');\n\nclass DataClonerViewDataView extends libPictView\n{\n\tconstructor(pFable, pOptions, pServiceHash)\n\t{\n\t\tsuper(pFable, pOptions, pServiceHash);\n\t}\n\n\tpopulateViewTableDropdown()\n\t{\n\t\tlet tmpSelect = document.getElementById('viewTable');\n\t\tif (!tmpSelect) return;\n\t\tlet tmpCurrentValue = tmpSelect.value;\n\n\t\ttmpSelect.innerHTML = '';\n\n\t\tlet tmpDeployedTables = this.pict.AppData.DataCloner.DeployedTables;\n\n\t\tif (!tmpDeployedTables || tmpDeployedTables.length === 0)\n\t\t{\n\t\t\tlet tmpOpt = document.createElement('option');\n\t\t\ttmpOpt.value = '';\n\t\t\ttmpOpt.textContent = '\\u2014 deploy tables first \\u2014';\n\t\t\ttmpSelect.appendChild(tmpOpt);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = 0; i < tmpDeployedTables.length; i++)\n\t\t{\n\t\t\tlet tmpOpt = document.createElement('option');\n\t\t\ttmpOpt.value = tmpDeployedTables[i];\n\t\t\ttmpOpt.textContent = tmpDeployedTables[i];\n\t\t\ttmpSelect.appendChild(tmpOpt);\n\t\t}\n\n\t\t// Restore previous selection if it exists\n\t\tif (tmpCurrentValue)\n\t\t{\n\t\t\ttmpSelect.value = tmpCurrentValue;\n\t\t}\n\t}\n\n\tloadTableData()\n\t{\n\t\tlet tmpTable = document.getElementById('viewTable').value;\n\t\tlet tmpLimit = parseInt(document.getElementById('viewLimit').value, 10) || 100;\n\n\t\tif (!tmpTable)\n\t\t{\n\t\t\tthis.pict.providers.DataCloner.setStatus('viewStatus', 'Select a table first.', 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pict.providers.DataCloner.setStatus('viewStatus', 'Loading ' + tmpTable + '...', 'info');\n\t\tdocument.getElementById('viewDataContainer').innerHTML = '';\n\n\t\tlet tmpSelf = this;\n\t\t// Use the standard Meadow CRUD list endpoint: /1.0/{Entity}s/0/{Cap}\n\t\tthis.pict.providers.DataCloner.api('GET', '/1.0/' + tmpTable + 's/0/' + tmpLimit)\n\t\t\t.then(function(pData)\n\t\t\t{\n\t\t\t\tif (!Array.isArray(pData))\n\t\t\t\t{\n\t\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', 'Unexpected response (not an array). The table may not be deployed yet.', 'error');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', pData.length + ' row(s) returned' + (pData.length >= tmpLimit ? ' (limit reached \\u2014 increase Max Rows to see more)' : '') + '.', 'ok');\n\t\t\t\ttmpSelf.renderDataTable(pData);\n\t\t\t})\n\t\t\t.catch(function(pError)\n\t\t\t{\n\t\t\t\ttmpSelf.pict.providers.DataCloner.setStatus('viewStatus', 'Request failed: ' + pError.message, 'error');\n\t\t\t});\n\t}\n\n\trenderDataTable(pRows)\n\t{\n\t\tlet tmpContainer = document.getElementById('viewDataContainer');\n\n\t\tif (!pRows || pRows.length === 0)\n\t\t{\n\t\t\ttmpContainer.innerHTML = '<p style=\"color:#666; font-size:0.9em; padding:8px\">No rows.</p>';\n\t\t\treturn;\n\t\t}\n\n\t\t// Collect all column names from the first row\n\t\tlet tmpColumns = Object.keys(pRows[0]);\n\n\t\tlet tmpHtml = '<table class=\"data-table\">';\n\t\ttmpHtml += '<thead><tr>';\n\t\tfor (let c = 0; c < tmpColumns.length; c++)\n\t\t{\n\t\t\ttmpHtml += '<th>' + this.pict.providers.DataCloner.escapeHtml(tmpColumns[c]) + '</th>';\n\t\t}\n\t\ttmpHtml += '</tr></thead>';\n\n\t\ttmpHtml += '<tbody>';\n\t\tfor (let r = 0; r < pRows.length; r++)\n\t\t{\n\t\t\ttmpHtml += '<tr>';\n\t\t\tfor (let c = 0; c < tmpColumns.length; c++)\n\t\t\t{\n\t\t\t\tlet tmpVal = pRows[r][tmpColumns[c]];\n\t\t\t\tlet tmpDisplay = (tmpVal === null || tmpVal === undefined) ? '' : String(tmpVal);\n\t\t\t\ttmpHtml += '<td title=\"' + this.pict.providers.DataCloner.escapeHtml(tmpDisplay) + '\">' + this.pict.providers.DataCloner.escapeHtml(tmpDisplay) + '</td>';\n\t\t\t}\n\t\t\ttmpHtml += '</tr>';\n\t\t}\n\t\ttmpHtml += '</tbody></table>';\n\n\t\ttmpContainer.innerHTML = tmpHtml;\n\t}\n}\n\nmodule.exports = DataClonerViewDataView;\n\nmodule.exports.default_configuration =\n{\n\tViewIdentifier: 'DataCloner-ViewData',\n\tDefaultRenderable: 'DataCloner-ViewData',\n\tDefaultDestinationAddress: '#DataCloner-Section-ViewData',\n\tCSS: /*css*/`\n.data-table { width: 100%; border-collapse: collapse; font-size: 0.8em; font-family: monospace; }\n.data-table th { background: #f8f9fa; font-weight: 600; text-align: left; padding: 4px 8px; border: 1px solid #ddd; white-space: nowrap; position: sticky; top: 0; }\n.data-table td { padding: 4px 8px; border: 1px solid #eee; white-space: nowrap; max-width: 300px; overflow: hidden; text-overflow: ellipsis; }\n.data-table tr:nth-child(even) { background: #fafafa; }\n.data-table tr:hover { background: #f0f7ff; }\n`,\n\tTemplates:\n\t[\n\t\t{\n\t\t\tHash: 'DataCloner-ViewData',\n\t\t\tTemplate: /*html*/`\n<div class=\"accordion-row\">\n\t<div class=\"accordion-number\">7</div>\n\t<div class=\"accordion-card\" id=\"section7\" data-section=\"7\">\n\t\t<div class=\"accordion-header\" onclick=\"pict.views['DataCloner-Layout'].toggleSection('section7')\">\n\t\t\t<div class=\"accordion-title\">View Data</div>\n\t\t\t<div class=\"accordion-preview\" id=\"preview7\">Browse synced table data</div>\n\t\t\t<div class=\"accordion-toggle\">▼</div>\n\t\t</div>\n\t\t<div class=\"accordion-body\">\n\t\t\t<div class=\"inline-group\">\n\t\t\t\t<div style=\"flex:1\">\n\t\t\t\t\t<label for=\"viewTable\">Table</label>\n\t\t\t\t\t<select id=\"viewTable\">\n\t\t\t\t\t\t<option value=\"\">\\u2014 deploy tables first \\u2014</option>\n\t\t\t\t\t</select>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 120px\">\n\t\t\t\t\t<label for=\"viewLimit\">Max Rows</label>\n\t\t\t\t\t<input type=\"number\" id=\"viewLimit\" value=\"100\" min=\"1\" max=\"10000\">\n\t\t\t\t</div>\n\t\t\t\t<div style=\"flex:0 0 auto; display:flex; align-items:flex-end\">\n\t\t\t\t\t<button class=\"primary\" onclick=\"pict.views['DataCloner-ViewData'].loadTableData()\">Load</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div id=\"viewStatus\"></div>\n\t\t\t<div id=\"viewDataContainer\" style=\"overflow-x:auto; margin-top:10px\"></div>\n\t\t</div>\n\t</div>\n</div>\n`\n\t\t}\n\t],\n\tRenderables:\n\t[\n\t\t{\n\t\t\tRenderableHash: 'DataCloner-ViewData',\n\t\t\tTemplateHash: 'DataCloner-ViewData',\n\t\t\tDestinationAddress: '#DataCloner-Section-ViewData'\n\t\t}\n\t]\n};\n"]}
|